home *** CD-ROM | disk | FTP | other *** search
/ Freelog 115 / FreelogNo115-MaiJuin2013.iso / Internet / Filezilla Server / FileZilla_Server-0_9_41.exe / source / misc / StdString.h < prev    next >
Text File  |  2011-11-06  |  136KB  |  4,158 lines

  1. // =============================================================================
  2. //  FILE:  StdString.h
  3. //  AUTHOR:    Joe O'Leary (with outside help noted in comments)
  4. //
  5. //
  6. //        If you find any bugs int his code, please let me know:
  7. //
  8. //                jmoleary@earthlink.net
  9. //                http://www.joeo.net/stdstring.htm (a bit outdated)
  10. //
  11. //      The latest version of this code should always be available at the
  12. //      following link:
  13. //
  14. //              http://www.joeo.net/code/StdString.zip (Dec 6, 2003)
  15. //
  16. //
  17. //  REMARKS:
  18. //        This header file declares the CStdStr template.  This template derives
  19. //        the Standard C++ Library basic_string<> template and add to it the
  20. //        the following conveniences:
  21. //            - The full MFC CString set of functions (including implicit cast)
  22. //            - writing to/reading from COM IStream interfaces
  23. //            - Functional objects for use in STL algorithms
  24. //
  25. //        From this template, we intstantiate two classes:  CStdStringA and
  26. //        CStdStringW.  The name "CStdString" is just a #define of one of these,
  27. //        based upone the UNICODE macro setting
  28. //
  29. //        This header also declares our own version of the MFC/ATL UNICODE-MBCS
  30. //        conversion macros.  Our version looks exactly like the Microsoft's to
  31. //        facilitate portability.
  32. //
  33. //    NOTE:
  34. //        If you you use this in an MFC or ATL build, you should include either
  35. //        afx.h or atlbase.h first, as appropriate.
  36. //
  37. //    PEOPLE WHO HAVE CONTRIBUTED TO THIS CLASS:
  38. //
  39. //        Several people have helped me iron out problems and othewise improve
  40. //        this class.  OK, this is a long list but in my own defense, this code
  41. //        has undergone two major rewrites.  Many of the improvements became
  42. //        necessary after I rewrote the code as a template.  Others helped me
  43. //        improve the CString facade.
  44. //
  45. //        Anyway, these people are (in chronological order):
  46. //
  47. //            - Pete the Plumber (???)
  48. //            - Julian Selman
  49. //            - Chris (of Melbsys)
  50. //            - Dave Plummer
  51. //            - John C Sipos
  52. //            - Chris Sells
  53. //            - Nigel Nunn
  54. //            - Fan Xia
  55. //            - Matthew Williams
  56. //            - Carl Engman
  57. //            - Mark Zeren
  58. //            - Craig Watson
  59. //            - Rich Zuris
  60. //            - Karim Ratib
  61. //            - Chris Conti
  62. //            - Baptiste Lepilleur
  63. //            - Greg Pickles
  64. //            - Jim Cline
  65. //            - Jeff Kohn
  66. //            - Todd Heckel
  67. //            - Ullrich PollΣhne
  68. //            - Joe Vitaterna
  69. //            - Joe Woodbury
  70. //            - Aaron (no last name)
  71. //            - Joldakowski (???)
  72. //            - Scott Hathaway
  73. //            - Eric Nitzche
  74. //            - Pablo Presedo
  75. //            - Farrokh Nejadlotfi
  76. //            - Jason Mills
  77. //            - Igor Kholodov
  78. //            - Mike Crusader
  79. //            - John James
  80. //            - Wang Haifeng
  81. //            - Tim Dowty
  82. //          - Arnt Witteveen
  83. //          - Glen Maynard
  84. //          - Paul DeMarco
  85. //          - Bagira (full name?)
  86. //          - Ronny Schulz
  87. //          - Jakko Van Hunen
  88. //            - Charles Godwin
  89. //            - Henk Demper
  90. //            - Greg Marr
  91. //            - Bill Carducci
  92. //            - Brian Groose
  93. //            - MKingman
  94. //
  95. //    REVISION HISTORY
  96. //
  97. //      2004-APR-22 - A big, big thank you to "MKingman" (whoever you are) for
  98. //                    finally spotting a silly little error in StdCodeCvt that
  99. //                    has been causing me (and users of CStdString) problems for
  100. //                    years in some relatively rare conversions.  I had reversed
  101. //                    two length arguments. 
  102. //
  103. //    2003-NOV-24 - Thanks to a bunch of people for helping me clean up many
  104. //                    compiler warnings (and yes, even a couple of actual compiler
  105. //                    errors).  These include Henk Demper for figuring out how
  106. //                    to make the Intellisense work on with CStdString on VC6,
  107. //                    something I was never able to do.  Greg Marr pointed out
  108. //                    a compiler warning about an unreferenced symbol and a
  109. //                    problem with my version of Load in MFC builds.  Bill
  110. //                    Carducci took a lot of time with me to help me figure out
  111. //                    why some implementations of the Standard C++ Library were
  112. //                    returning error codes for apparently successful conversions
  113. //                    between ASCII and UNICODE.  Finally thanks to Brian Groose
  114. //                    for helping me fix compiler signed unsigned warnings in
  115. //                    several functions.
  116. //
  117. //    2003-JUL-10 - Thanks to Charles Godwin for making me realize my 'FmtArg'
  118. //                    fixes had inadvertently broken the DLL-export code (which is
  119. //                  normally commented out.  I had to move it up higher.  Also
  120. //                    this helped me catch a bug in ssicoll that would prevent
  121. //                  compilation, otherwise.
  122. //
  123. //    2003-MAR-14 - Thanks to Jakko Van Hunen for pointing out a copy-and-paste
  124. //                  bug in one of the overloads of FmtArg.
  125. //
  126. //    2003-MAR-10 - Thanks to Ronny Schulz for (twice!) sending me some changes
  127. //                  to help CStdString build on SGI and for pointing out an
  128. //                  error in placement of my preprocessor macros for ssfmtmsg.
  129. //
  130. //    2002-NOV-26 - Thanks to Bagira for pointing out that my implementation of
  131. //                  SpanExcluding was not properly handling the case in which
  132. //                  the string did NOT contain any of the given characters
  133. //
  134. //    2002-OCT-21 - Many thanks to Paul DeMarco who was invaluable in helping me
  135. //                  get this code working with Borland's free compiler as well
  136. //                  as the Dev-C++ compiler (available free at SourceForge).
  137. //
  138. //    2002-SEP-13 - Thanks to Glen Maynard who helped me get rid of some loud
  139. //                  but harmless warnings that were showing up on g++.  Glen
  140. //                  also pointed out that some pre-declarations of FmtArg<>
  141. //                  specializations were unnecessary (and no good on G++)
  142. //
  143. //    2002-JUN-26 - Thanks to Arnt Witteveen for pointing out that I was using
  144. //                  static_cast<> in a place in which I should have been using
  145. //                  reinterpret_cast<> (the ctor for unsigned char strings).
  146. //                  That's what happens when I don't unit-test properly!
  147. //                  Arnt also noticed that CString was silently correcting the
  148. //                  'nCount' argument to Left() and Right() where CStdString was
  149. //                  not (and crashing if it was bad).  That is also now fixed!
  150. //
  151. //      2002-FEB-25 - Thanks to Tim Dowty for pointing out (and giving me the fix
  152. //                    for) a conversion problem with non-ASCII MBCS characters.
  153. //                    CStdString is now used in my favorite commercial MP3 player!
  154. //
  155. //      2001-DEC-06 - Thanks to Wang Haifeng for spotting a problem in one of the
  156. //                    assignment operators (for _bstr_t) that would cause compiler
  157. //                    errors when refcounting protection was turned off.
  158. //
  159. //      2001-NOV-27 - Remove calls to operator!= which involve reverse_iterators
  160. //                    due to a conflict with the rel_ops operator!=.  Thanks to
  161. //                    John James for pointing this out.
  162. //
  163. //    2001-OCT-29 - Added a minor range checking fix for the Mid function to
  164. //                    make it as forgiving as CString's version is.  Thanks to
  165. //                    Igor Kholodov for noticing this.  
  166. //                  - Added a specialization of std::swap for CStdString.  Thanks
  167. //                    to Mike Crusader for suggesting this!  It's commented out
  168. //                    because you're not supposed to inject your own code into the
  169. //                    'std' namespace.  But if you don't care about that, it's
  170. //                    there if you want it
  171. //                  - Thanks to Jason Mills for catching a case where CString was
  172. //                    more forgiving in the Delete() function than I was.
  173. //
  174. //      2001-JUN-06 - I was violating the Standard name lookup rules stated
  175. //                    in [14.6.2(3)].  None of the compilers I've tried so
  176. //                    far apparently caught this but HP-UX aCC 3.30 did.  The
  177. //                    fix was to add 'this->' prefixes in many places.
  178. //                    Thanks to Farrokh Nejadlotfi for this!
  179. //
  180. //      2001-APR-27 - StreamLoad was calculating the number of BYTES in one
  181. //                    case, not characters.  Thanks to Pablo Presedo for this.
  182. //
  183. //    2001-FEB-23 - Replace() had a bug which caused infinite loops if the
  184. //                    source string was empty.  Fixed thanks to Eric Nitzsche.
  185. //
  186. //    2001-FEB-23 - Scott Hathaway was a huge help in providing me with the
  187. //                    ability to build CStdString on Sun Unix systems.  He
  188. //                    sent me detailed build reports about what works and what
  189. //                    does not.  If CStdString compiles on your Unix box, you
  190. //                    can thank Scott for it.
  191. //
  192. //      2000-DEC-29 - Joldakowski noticed one overload of Insert failed to do a
  193. //                    range check as CString's does.  Now fixed -- thanks!
  194. //
  195. //      2000-NOV-07 - Aaron pointed out that I was calling static member
  196. //                    functions of char_traits via a temporary.  This was not
  197. //                    technically wrong, but it was unnecessary and caused
  198. //                    problems for poor old buggy VC5.  Thanks Aaron!
  199. //
  200. //      2000-JUL-11 - Joe Woodbury noted that the CString::Find docs don't match
  201. //                    what the CString::Find code really ends up doing.   I was
  202. //                    trying to match the docs.  Now I match the CString code
  203. //                  - Joe also caught me truncating strings for GetBuffer() calls
  204. //                    when the supplied length was less than the current length.
  205. //
  206. //      2000-MAY-25 - Better support for STLPORT's Standard library distribution
  207. //                  - Got rid of the NSP macro - it interfered with Koenig lookup
  208. //                  - Thanks to Joe Woodbury for catching a TrimLeft() bug that
  209. //                    I introduced in January.  Empty strings were not getting
  210. //                    trimmed
  211. //
  212. //      2000-APR-17 - Thanks to Joe Vitaterna for pointing out that ReverseFind
  213. //                    is supposed to be a const function.
  214. //
  215. //      2000-MAR-07 - Thanks to Ullrich PollΣhne for catching a range bug in one
  216. //                    of the overloads of assign.
  217. //
  218. //    2000-FEB-01 - You can now use CStdString on the Mac with CodeWarrior!
  219. //                    Thanks to Todd Heckel for helping out with this.
  220. //
  221. //      2000-JAN-23 - Thanks to Jim Cline for pointing out how I could make the
  222. //                    Trim() function more efficient.
  223. //                  - Thanks to Jeff Kohn for prompting me to find and fix a typo
  224. //                    in one of the addition operators that takes _bstr_t.
  225. //                  - Got rid of the .CPP file -  you only need StdString.h now!
  226. //
  227. //      1999-DEC-22 - Thanks to Greg Pickles for helping me identify a problem
  228. //                    with my implementation of CStdString::FormatV in which
  229. //                    resulting string might not be properly NULL terminated.
  230. //
  231. //      1999-DEC-06 - Chris Conti pointed yet another basic_string<> assignment
  232. //                    bug that MS has not fixed.  CStdString did nothing to fix
  233. //                    it either but it does now!  The bug was: create a string
  234. //                    longer than 31 characters, get a pointer to it (via c_str())
  235. //                    and then assign that pointer to the original string object.
  236. //                    The resulting string would be empty.  Not with CStdString!
  237. //
  238. //      1999-OCT-06 - BufferSet was erasing the string even when it was merely
  239. //                    supposed to shrink it.  Fixed.  Thanks to Chris Conti.
  240. //                  - Some of the Q172398 fixes were not checking for assignment-
  241. //                    to-self.  Fixed.  Thanks to Baptiste Lepilleur.
  242. //
  243. //      1999-AUG-20 - Improved Load() function to be more efficient by using 
  244. //                    SizeOfResource().  Thanks to Rich Zuris for this.
  245. //                  - Corrected resource ID constructor, again thanks to Rich.
  246. //                  - Fixed a bug that occurred with UNICODE characters above
  247. //                    the first 255 ANSI ones.  Thanks to Craig Watson. 
  248. //                  - Added missing overloads of TrimLeft() and TrimRight().
  249. //                    Thanks to Karim Ratib for pointing them out
  250. //
  251. //      1999-JUL-21 - Made all calls to GetBuf() with no args check length first.
  252. //
  253. //      1999-JUL-10 - Improved MFC/ATL independence of conversion macros
  254. //                  - Added SS_NO_REFCOUNT macro to allow you to disable any
  255. //                    reference-counting your basic_string<> impl. may do.
  256. //                  - Improved ReleaseBuffer() to be as forgiving as CString.
  257. //                    Thanks for Fan Xia for helping me find this and to
  258. //                    Matthew Williams for pointing it out directly.
  259. //
  260. //      1999-JUL-06 - Thanks to Nigel Nunn for catching a very sneaky bug in
  261. //                    ToLower/ToUpper.  They should call GetBuf() instead of
  262. //                    data() in order to ensure the changed string buffer is not
  263. //                    reference-counted (in those implementations that refcount).
  264. //
  265. //      1999-JUL-01 - Added a true CString facade.  Now you can use CStdString as
  266. //                    a drop-in replacement for CString.  If you find this useful,
  267. //                    you can thank Chris Sells for finally convincing me to give
  268. //                    in and implement it.
  269. //                  - Changed operators << and >> (for MFC CArchive) to serialize
  270. //                    EXACTLY as CString's do.  So now you can send a CString out
  271. //                    to a CArchive and later read it in as a CStdString.   I have
  272. //                    no idea why you would want to do this but you can. 
  273. //
  274. //      1999-JUN-21 - Changed the CStdString class into the CStdStr template.
  275. //                  - Fixed FormatV() to correctly decrement the loop counter.
  276. //                    This was harmless bug but a bug nevertheless.  Thanks to
  277. //                    Chris (of Melbsys) for pointing it out
  278. //                  - Changed Format() to try a normal stack-based array before
  279. //                    using to _alloca().
  280. //                  - Updated the text conversion macros to properly use code
  281. //                    pages and to fit in better in MFC/ATL builds.  In other
  282. //                    words, I copied Microsoft's conversion stuff again. 
  283. //                  - Added equivalents of CString::GetBuffer, GetBufferSetLength
  284. //                  - new sscpy() replacement of CStdString::CopyString()
  285. //                  - a Trim() function that combines TrimRight() and TrimLeft().
  286. //
  287. //      1999-MAR-13 - Corrected the "NotSpace" functional object to use _istpace()
  288. //                    instead of _isspace()   Thanks to Dave Plummer for this.
  289. //
  290. //      1999-FEB-26 - Removed errant line (left over from testing) that #defined
  291. //                    _MFC_VER.  Thanks to John C Sipos for noticing this.
  292. //
  293. //      1999-FEB-03 - Fixed a bug in a rarely-used overload of operator+() that
  294. //                    caused infinite recursion and stack overflow
  295. //                  - Added member functions to simplify the process of
  296. //                    persisting CStdStrings to/from DCOM IStream interfaces 
  297. //                  - Added functional objects (e.g. StdStringLessNoCase) that
  298. //                    allow CStdStrings to be used as keys STL map objects with
  299. //                    case-insensitive comparison 
  300. //                  - Added array indexing operators (i.e. operator[]).  I
  301. //                    originally assumed that these were unnecessary and would be
  302. //                    inherited from basic_string.  However, without them, Visual
  303. //                    C++ complains about ambiguous overloads when you try to use
  304. //                    them.  Thanks to Julian Selman to pointing this out. 
  305. //
  306. //      1998-FEB-?? - Added overloads of assign() function to completely account
  307. //                    for Q172398 bug.  Thanks to "Pete the Plumber" for this
  308. //
  309. //      1998-FEB-?? - Initial submission
  310. //
  311. // COPYRIGHT:
  312. //        2002 Joseph M. O'Leary.  This code is 100% free.  Use it anywhere you
  313. //      want.  Rewrite it, restructure it, whatever.  If you can write software
  314. //      that makes money off of it, good for you.  I kinda like capitalism. 
  315. //      Please don't blame me if it causes your $30 billion dollar satellite
  316. //      explode in orbit.  If you redistribute it in any form, I'd appreciate it
  317. //      if you would leave this notice here.
  318. // =============================================================================
  319.  
  320. // Avoid multiple inclusion the VC++ way,
  321. // Turn off browser references
  322. // Turn off unavoidable compiler warnings
  323.  
  324. #if defined(_MSC_VER) && (_MSC_VER > 1100)
  325.     #pragma once
  326.     #pragma component(browser, off, references, "CStdString")
  327.     #pragma warning (disable : 4290) // C++ Exception Specification ignored
  328.     #pragma warning (disable : 4127) // Conditional expression is constant
  329.     #pragma warning (disable : 4097) // typedef name used as synonym for class name
  330. #endif
  331.  
  332. // Borland warnings to turn off
  333.  
  334. #ifdef __BORLANDC__
  335.     #pragma option push -w-inl
  336. //    #pragma warn -inl   // Turn off inline function warnings
  337. #endif
  338.  
  339. #ifndef STDSTRING_H
  340. #define STDSTRING_H
  341.  
  342. // SS_IS_INTRESOURCE
  343. // -----------------
  344. //        A copy of IS_INTRESOURCE from VC7.  Because old VC6 version of winuser.h
  345. //        doesn't have this.
  346.  
  347. #define SS_IS_INTRESOURCE
  348.  
  349. #if !defined (SS_ANSI) && defined(_MSC_VER)
  350.     #undef SS_IS_INTRESOURCE
  351.     #if defined(_WIN64)
  352.         #define SS_IS_INTRESOURCE(_r) (((unsigned __int64)(_r) >> 16) == 0)
  353.     #else
  354.         #define SS_IS_INTRESOURCE(_r) (((unsigned long)(_r) >> 16) == 0)
  355.     #endif
  356. #endif
  357.  
  358.  
  359. // MACRO: SS_UNSIGNED
  360. // ------------------
  361. //      This macro causes the addition of a constructor and assignment operator
  362. //      which take unsigned characters.  CString has such functions and in order
  363. //      to provide maximum CString-compatability, this code needs them as well.
  364. //      In practice you will likely never need these functions...
  365.  
  366. //#define SS_UNSIGNED
  367.  
  368. #ifdef SS_ALLOW_UNSIGNED_CHARS
  369.     #define SS_UNSIGNED
  370. #endif
  371.  
  372. // MACRO: SS_SAFE_FORMAT
  373. // ---------------------
  374. //      This macro provides limited compatability with a questionable CString
  375. //      "feature".  You can define it in order to avoid a common problem that
  376. //      people encounter when switching from CString to CStdString.
  377. //
  378. //      To illustrate the problem -- With CString, you can do this:
  379. //
  380. //          CString sName("Joe");
  381. //          CString sTmp;
  382. //          sTmp.Format("My name is %s", sName);                    // WORKS!
  383. //
  384. //      However if you were to try this with CStdString, your program would
  385. //      crash.
  386. //
  387. //          CStdString sName("Joe");
  388. //          CStdString sTmp;
  389. //          sTmp.Format("My name is %s", sName);                    // CRASHES!
  390. //
  391. //      You must explicitly call c_str() or cast the object to the proper type
  392. //
  393. //          sTmp.Format("My name is %s", sName.c_str());            // WORKS!
  394. //          sTmp.Format("My name is %s", static_cast<PCSTR>(sName));// WORKS!
  395. //          sTmp.Format("My name is %s", (PCSTR)sName);// WORKS!
  396. //
  397. //      This is because it is illegal to pass anything but a POD type as a
  398. //      variadic argument to a variadic function (i.e. as one of the "..."
  399. //      arguments).  The type const char* is a POD type.  The type CStdString
  400. //      is not.  Of course, neither is the type CString, but CString lets you do
  401. //      it anyway due to the way they laid out the class in binary.  I have no
  402. //      control over this in CStdString since I derive from whatever
  403. //      implementation of basic_string is available.
  404. //
  405. //      However if you have legacy code (which does this) that you want to take
  406. //      out of the MFC world and you don't want to rewrite all your calls to
  407. //      Format(), then you can define this flag and it will no longer crash.
  408. //
  409. //      Note however that this ONLY works for Format(), not sprintf, fprintf, 
  410. //      etc.  If you pass a CStdString object to one of those functions, your
  411. //      program will crash.  Not much I can do to get around this, short of
  412. //      writing substitutes for those functions as well.
  413.  
  414. #define SS_SAFE_FORMAT  // use new template style Format() function
  415.  
  416.  
  417. // MACRO: SS_NO_IMPLICIT_CAST
  418. // --------------------------
  419. //      Some people don't like the implicit cast to const char* (or rather to
  420. //      const CT*) that CStdString (and MFC's CString) provide.  That was the
  421. //      whole reason I created this class in the first place, but hey, whatever
  422. //      bakes your cake.  Just #define this macro to get rid of the the implicit
  423. //      cast.
  424.  
  425. //#define SS_NO_IMPLICIT_CAST // gets rid of operator const CT*()
  426.  
  427.  
  428. // MACRO: SS_NO_REFCOUNT
  429. // ---------------------
  430. //        turns off reference counting at the assignment level.  Only needed
  431. //        for the version of basic_string<> that comes with Visual C++ versions
  432. //        6.0 or earlier, and only then in some heavily multithreaded scenarios.
  433. //        Uncomment it if you feel you need it.
  434.  
  435. //#define SS_NO_REFCOUNT
  436.  
  437. // MACRO: SS_WIN32
  438. // ---------------
  439. //      When this flag is set, we are building code for the Win32 platform and
  440. //      may use Win32 specific functions (such as LoadString).  This gives us
  441. //      a couple of nice extras for the code.
  442. //
  443. //      Obviously, Microsoft's is not the only compiler available for Win32 out
  444. //      there.  So I can't just check to see if _MSC_VER is defined to detect
  445. //      if I'm building on Win32.  So for now, if you use MS Visual C++ or
  446. //      Borland's compiler, I turn this on.  Otherwise you may turn it on
  447. //      yourself, if you prefer
  448. #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(_WIN32)
  449.     #define SS_WIN32
  450. #endif
  451.  
  452. // MACRO: SS_ANSI
  453. // --------------
  454. //      When this macro is defined, the code attempts only to use ANSI/ISO
  455. //      standard library functions to do it's work.  It will NOT attempt to use
  456. //      any Win32 of Visual C++ specific functions -- even if they are
  457. //      available.  You may define this flag yourself to prevent any Win32
  458. //      of VC++ specific functions from being called. 
  459.  
  460. // If we're not on Win32, we MUST use an ANSI build
  461.  
  462. #ifndef SS_WIN32
  463.     #if !defined(SS_NO_ANSI)
  464.         #define SS_ANSI
  465.     #endif
  466. #endif
  467.  
  468. // MACRO: SS_ALLOCA
  469. // ----------------
  470. //      Some implementations of the Standard C Library have a non-standard
  471. //      function known as alloca().  This functions allows one to allocate a
  472. //      variable amount of memory on the stack.  It is needed to implement
  473. //      the ASCII/MBCS conversion macros.
  474. //
  475. //      I wanted to find some way to determine automatically if alloca() is
  476. //        available on this platform via compiler flags but that is asking for
  477. //        trouble.  The crude test presented here will likely need fixing on
  478. //        other platforms.  Therefore I'll leave it up to you to fiddle with
  479. //        this test to determine if it exists.  Just make sure SS_ALLOCA is or
  480. //        is not defined as appropriate and you control this feature.
  481.  
  482. #if defined(_MSC_VER) && !defined(SS_ANSI)
  483.     #define SS_ALLOCA
  484. #endif
  485.  
  486. // MACRO: SS_MBCS
  487. // --------------
  488. //        Setting this macro means you are using MBCS characters.  In MSVC
  489. //        builds, this macro gets set automatically by detection of the
  490. //        preprocessor flag _MBCS.  For other platforms you may set it manually
  491. //        if you wish.  The only effect it currently has is to cause the
  492. //        allocation of more space for wchar_t --> char conversions.
  493. //        Note that MBCS does not mean UNICODE.
  494. //
  495. //    #define SS_MBCS
  496. //
  497. #ifdef _MBCS
  498.     #define SS_MBCS
  499. #endif
  500.  
  501.  
  502.  
  503. // Compiler Error regarding _UNICODE and UNICODE
  504. // -----------------------------------------------
  505. // Microsoft header files are screwy.  Sometimes they depend on a preprocessor 
  506. // flag named "_UNICODE".  Other times they check "UNICODE" (note the lack of
  507. // leading underscore in the second version".  In several places, they silently
  508. // "synchronize" these two flags this by defining one of the other was defined. 
  509. // In older version of this header , I used to try to do the same thing. 
  510. //
  511. // However experience has taught me that this is a bad idea.  You get weird
  512. // compiler errors that seem to indicate things like LPWSTR and LPTSTR not being
  513. // equivalent in UNICODE builds, stuff like that (when they MUST be in a proper
  514. // UNICODE  build).  You end up scratching your head and saying, "But that HAS
  515. // to compile!".
  516. //
  517. // So what should you do if you get this error?
  518. //
  519. // Make sure that both macros (_UNICODE and UNICODE) are defined before this
  520. // file is included.  You can do that by either
  521. //
  522. //        a) defining both yourself before any files get included
  523. //        b) including the proper MS headers in the proper order
  524. //        c) including this file before any other file, uncommenting
  525. //           the #defines below, and commenting out the #errors
  526. //
  527. //    Personally I recommend solution a) but it's your call.
  528.  
  529. #ifdef _MSC_VER
  530.     #if defined (_UNICODE) && !defined (UNICODE)
  531.         #error UNICODE defined  but not UNICODE
  532.     //    #define UNICODE  // no longer silently fix this
  533.     #endif
  534.     #if defined (UNICODE) && !defined (_UNICODE)
  535.         #error Warning, UNICODE defined  but not _UNICODE
  536.     //    #define _UNICODE  // no longer silently fix this
  537.     #endif
  538. #endif
  539.  
  540.  
  541. // -----------------------------------------------------------------------------
  542. // MIN and MAX.  The Standard C++ template versions go by so many names (at
  543. // at least in the MS implementation) that you never know what's available 
  544. // -----------------------------------------------------------------------------
  545. template<class Type>
  546. inline const Type& SSMIN(const Type& arg1, const Type& arg2)
  547. {
  548.     return arg2 < arg1 ? arg2 : arg1;
  549. }
  550. template<class Type>
  551. inline const Type& SSMAX(const Type& arg1, const Type& arg2)
  552. {
  553.     return arg2 > arg1 ? arg2 : arg1;
  554. }
  555.  
  556. // If they have not #included W32Base.h (part of my W32 utility library) then
  557. // we need to define some stuff.  Otherwise, this is all defined there.
  558.  
  559. #if !defined(W32BASE_H)
  560.  
  561.     // If they want us to use only standard C++ stuff (no Win32 stuff)
  562.  
  563.     #ifdef SS_ANSI
  564.  
  565.         // On Win32 we have TCHAR.H so just include it.  This is NOT violating
  566.         // the spirit of SS_ANSI as we are not calling any Win32 functions here.
  567.         
  568.         #ifdef SS_WIN32
  569.  
  570.             #include <TCHAR.H>
  571.             #include <WTYPES.H>
  572.             #ifndef STRICT
  573.                 #define STRICT
  574.             #endif
  575.  
  576.         // ... but on non-Win32 platforms, we must #define the types we need.
  577.  
  578.         #else
  579.  
  580.             typedef const char*        PCSTR;
  581.             typedef char*            PSTR;
  582.             typedef const wchar_t*    PCWSTR;
  583.             typedef wchar_t*        PWSTR;
  584.             #ifdef UNICODE
  585.                 typedef wchar_t        TCHAR;
  586.             #else
  587.                 typedef char        TCHAR;
  588.             #endif
  589.             typedef wchar_t            OLECHAR;
  590.  
  591.         #endif    // #ifndef _WIN32
  592.  
  593.  
  594.         // Make sure ASSERT and verify are defined using only ANSI stuff
  595.  
  596.         #ifndef ASSERT
  597.             #include <assert.h>
  598.             #define ASSERT(f) assert((f))
  599.         #endif
  600.         #ifndef VERIFY
  601.             #ifdef _DEBUG
  602.                 #define VERIFY(x) ASSERT((x))
  603.             #else
  604.                 #define VERIFY(x) x
  605.             #endif
  606.         #endif
  607.  
  608.     #else // ...else SS_ANSI is NOT defined
  609.  
  610.         #include <TCHAR.H>
  611.         #include <WTYPES.H>
  612.         #ifndef STRICT
  613.             #define STRICT
  614.         #endif
  615.  
  616.         // Make sure ASSERT and verify are defined
  617.  
  618.         #ifndef ASSERT
  619.             #include <crtdbg.h>
  620.             #define ASSERT(f) _ASSERTE((f))
  621.         #endif
  622.         #ifndef VERIFY
  623.             #ifdef _DEBUG
  624.                 #define VERIFY(x) ASSERT((x))
  625.             #else
  626.                 #define VERIFY(x) x
  627.             #endif
  628.         #endif
  629.  
  630.     #endif // #ifdef SS_ANSI
  631.  
  632.     #ifndef UNUSED
  633.         #define UNUSED(x) x
  634.     #endif
  635.  
  636. #endif // #ifndef W32BASE_H
  637.  
  638. // Standard headers needed
  639.  
  640. #include <string>            // basic_string
  641. #include <algorithm>        // for_each, etc.
  642. #include <functional>        // for StdStringLessNoCase, et al
  643. #include <locale>        // for various facets
  644.  
  645. // If this is a recent enough version of VC include comdef.h, so we can write
  646. // member functions to deal with COM types & compiler support classes e.g.
  647. // _bstr_t
  648.  
  649. #if defined (_MSC_VER) && (_MSC_VER >= 1100)
  650.     #include <comdef.h>
  651.     #define SS_INC_COMDEF        // signal that we #included MS comdef.h file
  652.     #define STDSTRING_INC_COMDEF
  653.     #define SS_NOTHROW __declspec(nothrow)
  654. #else
  655.     #define SS_NOTHROW
  656. #endif
  657.  
  658. #ifndef TRACE
  659.     #define TRACE_DEFINED_HERE
  660.     #define TRACE
  661. #endif
  662.  
  663. // Microsoft defines PCSTR, PCWSTR, etc, but no PCTSTR.  I hate to use the
  664. // versions with the "L" in front of them because that's a leftover from Win 16
  665. // days, even though it evaluates to the same thing.  Therefore, Define a PCSTR
  666. // as an LPCTSTR.
  667.  
  668. #if !defined(PCTSTR) && !defined(PCTSTR_DEFINED)
  669.     typedef const TCHAR*            PCTSTR;
  670.     #define PCTSTR_DEFINED
  671. #endif
  672.  
  673. #if !defined(PCOLESTR) && !defined(PCOLESTR_DEFINED)
  674.     typedef const OLECHAR*            PCOLESTR;
  675.     #define PCOLESTR_DEFINED
  676. #endif
  677.  
  678. #if !defined(POLESTR) && !defined(POLESTR_DEFINED)
  679.     typedef OLECHAR*                POLESTR;
  680.     #define POLESTR_DEFINED
  681. #endif
  682.  
  683. #if !defined(PCUSTR) && !defined(PCUSTR_DEFINED)
  684.     typedef const unsigned char*    PCUSTR;
  685.     typedef unsigned char*            PUSTR;
  686.     #define PCUSTR_DEFINED
  687. #endif
  688.  
  689.  
  690. // SGI compiler 7.3 doesnt know these  types - oh and btw, remember to use
  691. // -LANG:std in the CXX Flags
  692. #if defined(__sgi)
  693.     typedef unsigned long           DWORD;
  694.     typedef void *                  LPCVOID;
  695. #endif
  696.  
  697.  
  698. // SS_USE_FACET macro and why we need it:
  699. //
  700. // Since I'm a good little Standard C++ programmer, I use locales.  Thus, I
  701. // need to make use of the use_facet<> template function here.   Unfortunately,
  702. // this need is complicated by the fact the MS' implementation of the Standard
  703. // C++ Library has a non-standard version of use_facet that takes more
  704. // arguments than the standard dictates.  Since I'm trying to write CStdString
  705. // to work with any version of the Standard library, this presents a problem.
  706. //
  707. // The upshot of this is that I can't do 'use_facet' directly.  The MS' docs
  708. // tell me that I have to use a macro, _USE() instead.  Since _USE obviously
  709. // won't be available in other implementations, this means that I have to write
  710. // my OWN macro -- SS_USE_FACET -- that evaluates either to _USE or to the
  711. // standard, use_facet.
  712. //
  713. // If you are having trouble with the SS_USE_FACET macro, in your implementation
  714. // of the Standard C++ Library, you can define your own version of SS_USE_FACET.
  715. #ifndef schMSG
  716.     #define schSTR(x)       #x
  717.     #define schSTR2(x)    schSTR(x)
  718.     #define schMSG(desc) message(__FILE__ "(" schSTR2(__LINE__) "):" #desc)
  719. #endif
  720.  
  721. #ifndef SS_USE_FACET
  722.     // STLPort #defines a macro (__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) for
  723.     // all MSVC builds, erroneously in my opinion.  It causes problems for
  724.     // my SS_ANSI builds.  In my code, I always comment out that line.  You'll
  725.     // find it in   \stlport\config\stl_msvc.h
  726.     #if defined(__SGI_STL_PORT) && (__SGI_STL_PORT >= 0x400 )
  727.         #if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) && defined(_MSC_VER)
  728.             #ifdef SS_ANSI
  729.                 #pragma schMSG(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS defined!!)
  730.             #endif
  731.         #endif
  732.         #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
  733.     #elif defined(_MSC_VER )
  734.     #define SS_USE_FACET(loc, fac) std::_USE(loc, fac)
  735.  
  736.     // ...and
  737.     #elif defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE)
  738.         #define SS_USE_FACET(loc, fac) std::use_facet(loc, (fac*)0)
  739.     #else
  740.         #define SS_USE_FACET(loc, fac) std::use_facet<fac >(loc)
  741.     #endif
  742. #endif
  743.  
  744. // =============================================================================
  745. // UNICODE/MBCS conversion macros.  Made to work just like the MFC/ATL ones.
  746. // =============================================================================
  747.  
  748. #include <wchar.h>      // Added to Std Library with Amendment #1.
  749.  
  750. // First define the conversion helper functions.  We define these regardless of
  751. // any preprocessor macro settings since their names won't collide. 
  752.  
  753. // Not sure if we need all these headers.   I believe ANSI says we do.
  754.  
  755. #include <stdio.h>
  756. #include <stdarg.h>
  757. #include <wctype.h>
  758. #include <ctype.h>
  759. #include <stdlib.h>
  760. #ifndef va_start
  761.     #include <varargs.h>
  762. #endif
  763.  
  764. // StdCodeCvt - made to look like Win32 functions WideCharToMultiByte
  765. //                and MultiByteToWideChar but uses locales in SS_ANSI
  766. //                builds.  There are a number of overloads.
  767. //              First argument is the destination buffer.
  768. //              Second argument is the source buffer
  769. //#if defined (SS_ANSI) || !defined (SS_WIN32)
  770.  
  771. // 'SSCodeCvt' - shorthand name for the codecvt facet we use
  772.  
  773. typedef std::codecvt<wchar_t, char, mbstate_t> SSCodeCvt;
  774.  
  775. inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCSTR pSrcA, int nSrc,
  776.     const std::locale& loc=std::locale())
  777. {
  778.  
  779.     ASSERT(0 != pSrcA);
  780.     ASSERT(0 != pDstW);
  781.  
  782.     pDstW[0]                    = '\0';    
  783.  
  784.     if ( nSrc > 0 )
  785.     {
  786.         PCSTR pNextSrcA            = pSrcA;
  787.         PWSTR pNextDstW            = pDstW;
  788.         SSCodeCvt::result res    = SSCodeCvt::ok;
  789.         const SSCodeCvt& conv    = SS_USE_FACET(loc, SSCodeCvt);
  790.         SSCodeCvt::state_type st= { 0 };
  791.         res                        = conv.in(st,
  792.                                     pSrcA, pSrcA + nSrc, pNextSrcA,
  793.                                     pDstW, pDstW + nDst, pNextDstW);
  794.  
  795.         ASSERT(SSCodeCvt::ok == res);
  796.         ASSERT(SSCodeCvt::error != res);
  797.         ASSERT(pNextDstW >= pDstW);
  798.         ASSERT(pNextSrcA >= pSrcA);
  799.  
  800.         // Null terminate the converted string
  801.  
  802.         if ( pNextDstW - pDstW > nDst )
  803.             *(pDstW + nDst) = '\0';
  804.         else
  805.             *pNextDstW = '\0';
  806.     }
  807.     return pDstW;
  808. }
  809. inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCUSTR pSrcA, int nSrc,
  810.     const std::locale& loc=std::locale())
  811. {
  812.     return StdCodeCvt(pDstW, nDst, (PCSTR)pSrcA, nSrc, loc);
  813. }
  814.  
  815. inline PSTR StdCodeCvt(PSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
  816.     const std::locale& loc=std::locale())
  817. {
  818.     ASSERT(0 != pDstA);
  819.     ASSERT(0 != pSrcW);
  820.  
  821.     pDstA[0]                    = '\0';    
  822.  
  823.     if ( nSrc > 0 )
  824.     {
  825.         PSTR pNextDstA            = pDstA;
  826.         PCWSTR pNextSrcW        = pSrcW;
  827.         SSCodeCvt::result res    = SSCodeCvt::ok;
  828.         const SSCodeCvt& conv    = SS_USE_FACET(loc, SSCodeCvt);
  829.         SSCodeCvt::state_type st= { 0 };
  830.         res                        = conv.out(st,
  831.                                     pSrcW, pSrcW + nSrc, pNextSrcW,
  832.                                     pDstA, pDstA + nDst, pNextDstA);
  833.  
  834.         ASSERT(SSCodeCvt::error != res);
  835.         ASSERT(SSCodeCvt::ok == res);    // strict, comment out for sanity
  836.         ASSERT(pNextDstA >= pDstA);
  837.         ASSERT(pNextSrcW >= pSrcW);
  838.  
  839.         // Null terminate the converted string
  840.  
  841.         if ( pNextDstA - pDstA > nDst )
  842.             *(pDstA + nDst) = '\0';
  843.         else
  844.             *pNextDstA = '\0';
  845.     }
  846.     return pDstA;
  847. }
  848. inline PUSTR StdCodeCvt(PUSTR pDstA, int nDst, PCWSTR pSrcW, int nSrc,
  849.     const std::locale& loc=std::locale())
  850. {
  851.     return (PUSTR)StdCodeCvt((PSTR)pDstA, nDst, pSrcW, nSrc, loc);
  852. }
  853. /*
  854. #else   // ...or are we doing things assuming win32 and Visual C++?
  855.  
  856.     inline PWSTR StdCodeCvt(PWSTR pDstW, int nDst, PCSTR pSrcA, int nSrc, UINT acp=CP_ACP)
  857.     {
  858.         ASSERT(0 != pSrcA);
  859.         ASSERT(0 != pDstW);
  860.         pW[0] = '\0';
  861.         MultiByteToWideChar(acp, 0, pSrcA, nSrc, pDstW, nDst);
  862.         return pW;
  863.     }
  864.     inline PWSTR StdCodeCvt(PWSTR pDstW, nDst, PCUSTR pSrcA, int nSrc, UINT acp=CP_ACP)
  865.     {
  866.         return StdCodeCvt(pDstW, nDst, (PCSTR)pSrcA, nSrc, acp);
  867.     }
  868.  
  869.     inline PSTR StdCodeCvt(PSTR pDstA, nDst PCWSTR pSrcW, int nSrc, UINT acp=CP_ACP)
  870.     {
  871.         ASSERT(0 != pDstA);
  872.         ASSERT(0 != pSrcW);
  873.         pA[0] = '\0';
  874.         WideCharToMultiByte(acp, 0, pSrcW, nSrc, pDstA, nDst, 0, 0);
  875.         return pA;
  876.     }
  877.     inline PUSTR StdCodeCvt(PUSTR pDstA, nDst, PCWSTR pSrcW, int nSrc, UINT acp=CP_ACP)
  878.     {
  879.         return (PUSTR)StdCodeCvt((PSTR)pDstA, nDst, pSrcW, nSrc, acp);
  880.     }
  881.  
  882. #endif
  883. */
  884.  
  885. // Unicode/MBCS conversion macros are only available on implementations of
  886. // the "C" library that have the non-standard _alloca function.  As far as I
  887. // know that's only Microsoft's though I've heard that the function exists
  888. // elsewhere.  
  889.     
  890. #if defined(SS_ALLOCA) && !defined SS_NO_CONVERSION
  891.  
  892.     #include <malloc.h>    // needed for _alloca
  893.  
  894.     // Define our conversion macros to look exactly like Microsoft's to
  895.     // facilitate using this stuff both with and without MFC/ATL
  896.  
  897.     #ifdef _CONVERSION_USES_THREAD_LOCALE
  898.  
  899.         #ifndef _DEBUG
  900.             #define SSCVT int _cvt; _cvt; UINT _acp=GetACP(); \
  901.                 _acp; PCWSTR _pw; _pw; PCSTR _pa; _pa
  902.         #else
  903.             #define SSCVT int _cvt = 0; _cvt; UINT _acp=GetACP();\
  904.                  _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
  905.         #endif
  906.         #define SSA2W(pa) (\
  907.             ((_pa = pa) == 0) ? 0 : (\
  908.                 _cvt = (sslen(_pa)),\
  909.                 StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
  910.                             _pa, _cvt, _acp)))
  911.         #define SSW2A(pw) (\
  912.             ((_pw = pw) == 0) ? 0 : (\
  913.                 _cvt = sslen(_pw), \
  914.                 StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
  915.                     _pw, _cvt, _acp)))
  916.     #else
  917.  
  918.         #ifndef _DEBUG
  919.             #define SSCVT int _cvt; _cvt; UINT _acp=CP_ACP; _acp;\
  920.                  PCWSTR _pw; _pw; PCSTR _pa; _pa
  921.         #else
  922.             #define SSCVT int _cvt = 0; _cvt; UINT _acp=CP_ACP; \
  923.                 _acp; PCWSTR _pw=0; _pw; PCSTR _pa=0; _pa
  924.         #endif
  925.         #define SSA2W(pa) (\
  926.             ((_pa = pa) == 0) ? 0 : (\
  927.                 _cvt = (sslen(_pa)),\
  928.                 StdCodeCvt((PWSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
  929.                     _pa, _cvt)))
  930.         #define SSW2A(pw) (\
  931.             ((_pw = pw) == 0) ? 0 : (\
  932.                 _cvt = (sslen(_pw)),\
  933.                 StdCodeCvt((LPSTR) _alloca((_cvt+1)*2), (_cvt+1)*2, \
  934.                     _pw, _cvt)))
  935.     #endif
  936.  
  937.     #define SSA2CW(pa) ((PCWSTR)SSA2W((pa)))
  938.     #define SSW2CA(pw) ((PCSTR)SSW2A((pw)))
  939.  
  940.     #ifdef UNICODE
  941.         #define SST2A    SSW2A
  942.         #define SSA2T    SSA2W
  943.         #define SST2CA    SSW2CA
  944.         #define SSA2CT    SSA2CW
  945.         // (Did you get a compiler error here about not being able to convert
  946.         // PTSTR into PWSTR?  Then your _UNICODE and UNICODE flags are messed 
  947.         // up.  Best bet: #define BOTH macros before including any MS headers.)
  948.         inline PWSTR    SST2W(PTSTR p)            { return p; }
  949.         inline PTSTR    SSW2T(PWSTR p)            { return p; }
  950.         inline PCWSTR    SST2CW(PCTSTR p)        { return p; }
  951.         inline PCTSTR    SSW2CT(PCWSTR p)        { return p; }
  952.     #else
  953.         #define SST2W    SSA2W
  954.         #define SSW2T    SSW2A
  955.         #define SST2CW    SSA2CW
  956.         #define SSW2CT    SSW2CA
  957.         inline PSTR        SST2A(PTSTR p)            { return p; }
  958.         inline PTSTR    SSA2T(PSTR p)            { return p; }
  959.         inline PCSTR    SST2CA(PCTSTR p)        { return p; }
  960.         inline PCTSTR    SSA2CT(PCSTR p)            { return p; }
  961.     #endif // #ifdef UNICODE
  962.  
  963.     #if defined(UNICODE)
  964.     // in these cases the default (TCHAR) is the same as OLECHAR
  965.         inline PCOLESTR    SST2COLE(PCTSTR p)        { return p; }
  966.         inline PCTSTR    SSOLE2CT(PCOLESTR p)    { return p; }
  967.         inline POLESTR    SST2OLE(PTSTR p)        { return p; }
  968.         inline PTSTR    SSOLE2T(POLESTR p)        { return p; }
  969.     #elif defined(OLE2ANSI)
  970.     // in these cases the default (TCHAR) is the same as OLECHAR
  971.         inline PCOLESTR    SST2COLE(PCTSTR p)        { return p; }
  972.         inline PCTSTR    SSOLE2CT(PCOLESTR p)    { return p; }
  973.         inline POLESTR    SST2OLE(PTSTR p)        { return p; }
  974.         inline PTSTR    SSOLE2T(POLESTR p)        { return p; }
  975.     #else
  976.         //CharNextW doesn't work on Win95 so we use this
  977.         #define SST2COLE(pa)    SSA2CW((pa))
  978.         #define SST2OLE(pa)        SSA2W((pa))
  979.         #define SSOLE2CT(po)    SSW2CA((po))
  980.         #define SSOLE2T(po)        SSW2A((po))
  981.     #endif
  982.  
  983.     #ifdef OLE2ANSI
  984.         #define SSW2OLE        SSW2A
  985.         #define SSOLE2W        SSA2W
  986.         #define SSW2COLE    SSW2CA
  987.         #define SSOLE2CW    SSA2CW
  988.         inline POLESTR        SSA2OLE(PSTR p)        { return p; }
  989.         inline PSTR            SSOLE2A(POLESTR p)    { return p; }
  990.         inline PCOLESTR        SSA2COLE(PCSTR p)    { return p; }
  991.         inline PCSTR        SSOLE2CA(PCOLESTR p){ return p; }
  992.     #else
  993.         #define SSA2OLE        SSA2W
  994.         #define SSOLE2A        SSW2A
  995.         #define SSA2COLE    SSA2CW
  996.         #define SSOLE2CA    SSW2CA
  997.         inline POLESTR        SSW2OLE(PWSTR p)    { return p; }
  998.         inline PWSTR        SSOLE2W(POLESTR p)    { return p; }
  999.         inline PCOLESTR        SSW2COLE(PCWSTR p)    { return p; }
  1000.         inline PCWSTR        SSOLE2CW(PCOLESTR p){ return p; }
  1001.     #endif
  1002.  
  1003.     // Above we've defined macros that look like MS' but all have
  1004.     // an 'SS' prefix.  Now we need the real macros.  We'll either
  1005.     // get them from the macros above or from MFC/ATL. 
  1006.  
  1007.     #if defined (USES_CONVERSION)
  1008.  
  1009.         #define _NO_STDCONVERSION    // just to be consistent
  1010.  
  1011.     #else
  1012.  
  1013.         #ifdef _MFC_VER
  1014.  
  1015.             #include <afxconv.h>
  1016.             #define _NO_STDCONVERSION // just to be consistent
  1017.  
  1018.         #else
  1019.  
  1020.             #define USES_CONVERSION SSCVT
  1021.             #define A2CW            SSA2CW
  1022.             #define W2CA            SSW2CA
  1023.             #define T2A                SST2A
  1024.             #define A2T                SSA2T
  1025.             #define T2W                SST2W
  1026.             #define W2T                SSW2T
  1027.             #define T2CA            SST2CA
  1028.             #define A2CT            SSA2CT
  1029.             #define T2CW            SST2CW
  1030.             #define W2CT            SSW2CT
  1031.             #define ocslen            sslen
  1032.             #define ocscpy            sscpy
  1033.             #define T2COLE            SST2COLE
  1034.             #define OLE2CT            SSOLE2CT
  1035.             #define T2OLE            SST2COLE
  1036.             #define OLE2T            SSOLE2CT
  1037.             #define A2OLE            SSA2OLE
  1038.             #define OLE2A            SSOLE2A
  1039.             #define W2OLE            SSW2OLE
  1040.             #define OLE2W            SSOLE2W
  1041.             #define A2COLE            SSA2COLE
  1042.             #define OLE2CA            SSOLE2CA
  1043.             #define W2COLE            SSW2COLE
  1044.             #define OLE2CW            SSOLE2CW
  1045.     
  1046.         #endif // #ifdef _MFC_VER
  1047.     #endif // #ifndef USES_CONVERSION
  1048. #endif // #ifndef SS_NO_CONVERSION
  1049.  
  1050. // Define ostring - generic name for std::basic_string<OLECHAR>
  1051.  
  1052. #if !defined(ostring) && !defined(OSTRING_DEFINED)
  1053.     typedef std::basic_string<OLECHAR> ostring;
  1054.     #define OSTRING_DEFINED
  1055. #endif
  1056.  
  1057. // StdCodeCvt when there's no conversion to be done
  1058. inline PSTR StdCodeCvt(PSTR pDst, int nDst, PCSTR pSrc, int nSrc)
  1059. {
  1060.     int nChars = SSMIN(nSrc, nDst);
  1061.  
  1062.     if ( nChars > 0 )
  1063.     {
  1064.         pDst[0]                = '\0';
  1065.         std::basic_string<char>::traits_type::copy(pDst, pSrc, nChars);
  1066. //        std::char_traits<char>::copy(pDst, pSrc, nChars);
  1067.         pDst[nChars]    = '\0';
  1068.     }
  1069.  
  1070.     return pDst;
  1071. }
  1072. inline PSTR StdCodeCvt(PSTR pDst, int nDst, PCUSTR pSrc, int nSrc)
  1073. {
  1074.     return StdCodeCvt(pDst, nDst, (PCSTR)pSrc, nSrc);
  1075. }
  1076. inline PUSTR StdCodeCvt(PUSTR pDst, int nDst, PCSTR pSrc, int nSrc)
  1077. {
  1078.     return (PUSTR)StdCodeCvt((PSTR)pDst, nDst, pSrc, nSrc);
  1079. }
  1080.  
  1081. inline PWSTR StdCodeCvt(PWSTR pDst, int nDst, PCWSTR pSrc, int nSrc)
  1082. {
  1083.     int nChars = SSMIN(nSrc, nDst);
  1084.  
  1085.     if ( nChars > 0 )
  1086.     {
  1087.         pDst[0]                = '\0';
  1088.         std::basic_string<wchar_t>::traits_type::copy(pDst, pSrc, nChars);
  1089. //        std::char_traits<wchar_t>::copy(pDst, pSrc, nChars);
  1090.         pDst[nChars]    = '\0';
  1091.     }
  1092.  
  1093.     return pDst;
  1094. }
  1095.  
  1096.  
  1097. // Define tstring -- generic name for std::basic_string<TCHAR>
  1098.  
  1099. #if !defined(tstring) && !defined(TSTRING_DEFINED)
  1100.     typedef std::basic_string<TCHAR> tstring;
  1101.     #define TSTRING_DEFINED
  1102. #endif
  1103.  
  1104. // a very shorthand way of applying the fix for KB problem Q172398
  1105. // (basic_string assignment bug)
  1106.  
  1107. #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
  1108.     #define Q172398(x) (x).erase()
  1109. #else
  1110.     #define Q172398(x)
  1111. #endif
  1112.  
  1113. // =============================================================================
  1114. // INLINE FUNCTIONS ON WHICH CSTDSTRING RELIES
  1115. //
  1116. // Usually for generic text mapping, we rely on preprocessor macro definitions
  1117. // to map to string functions.  However the CStdStr<> template cannot use
  1118. // macro-based generic text mappings because its character types do not get
  1119. // resolved until template processing which comes AFTER macro processing.  In
  1120. // other words, the preprocessor macro UNICODE is of little help to us in the
  1121. // CStdStr template
  1122. //
  1123. // Therefore, to keep the CStdStr declaration simple, we have these inline
  1124. // functions.  The template calls them often.  Since they are inline (and NOT
  1125. // exported when this is built as a DLL), they will probably be resolved away
  1126. // to nothing. 
  1127. //
  1128. // Without these functions, the CStdStr<> template would probably have to broken
  1129. // out into two, almost identical classes.  Either that or it would be a huge,
  1130. // convoluted mess, with tons of "if" statements all over the place checking the
  1131. // size of template parameter CT.
  1132. // 
  1133. // In several cases, you will see two versions of each function.  One version is
  1134. // the more portable, standard way of doing things, while the other is the
  1135. // non-standard, but often significantly faster Visual C++ way.
  1136. // =============================================================================
  1137.  
  1138. // If they defined SS_NO_REFCOUNT, then we must convert all assignments
  1139.  
  1140. #ifdef SS_NO_REFCOUNT
  1141.     #define SSREF(x) (x).c_str()
  1142. #else
  1143.     #define SSREF(x) (x)
  1144. #endif
  1145.  
  1146. // -----------------------------------------------------------------------------
  1147. // sslen: strlen/wcslen wrappers
  1148. // -----------------------------------------------------------------------------
  1149. template<typename CT> inline int sslen(const CT* pT)
  1150. {
  1151.     return 0 == pT ? 0 : (int)std::basic_string<CT>::traits_type::length(pT);
  1152. //    return 0 == pT ? 0 : std::char_traits<CT>::length(pT);
  1153. }
  1154. inline SS_NOTHROW int sslen(const std::string& s)
  1155. {
  1156.     return static_cast<int>(s.length());
  1157. }
  1158. inline SS_NOTHROW int sslen(const std::wstring& s)
  1159. {
  1160.     return static_cast<int>(s.length());
  1161. }
  1162.  
  1163. // -----------------------------------------------------------------------------
  1164. // sstolower/sstoupper -- convert characters to upper/lower case
  1165. // -----------------------------------------------------------------------------
  1166. template<typename CT>
  1167. inline CT sstolower(const CT& t, const std::locale& loc = std::locale())
  1168. {
  1169.     return std::tolower<CT>(t, loc);
  1170. }
  1171. template<typename CT>
  1172. inline CT sstoupper(const CT& t, const std::locale& loc = std::locale())
  1173. {
  1174.     return std::toupper<CT>(t, loc);
  1175. }
  1176.  
  1177. // -----------------------------------------------------------------------------
  1178. // ssasn: assignment functions -- assign "sSrc" to "sDst"
  1179. // -----------------------------------------------------------------------------
  1180. typedef std::string::size_type        SS_SIZETYPE; // just for shorthand, really
  1181. typedef std::string::pointer        SS_PTRTYPE;  
  1182. typedef std::wstring::size_type        SW_SIZETYPE;
  1183. typedef std::wstring::pointer        SW_PTRTYPE;  
  1184.  
  1185. inline void    ssasn(std::string& sDst, const std::string& sSrc)
  1186. {
  1187.     if ( sDst.c_str() != sSrc.c_str() )
  1188.     {
  1189.         sDst.erase();
  1190.         sDst.assign(SSREF(sSrc));
  1191.     }
  1192. }
  1193. inline void    ssasn(std::string& sDst, PCSTR pA)
  1194. {
  1195.     // Watch out for NULLs, as always.
  1196.  
  1197.     if ( 0 == pA )
  1198.     {
  1199.         sDst.erase();
  1200.     }
  1201.  
  1202.     // If pA actually points to part of sDst, we must NOT erase(), but
  1203.     // rather take a substring
  1204.  
  1205.     else if ( pA >= sDst.c_str() && pA <= sDst.c_str() + sDst.size() )
  1206.     {
  1207.         sDst =sDst.substr(static_cast<SS_SIZETYPE>(pA-sDst.c_str()));
  1208.     }
  1209.  
  1210.     // Otherwise (most cases) apply the assignment bug fix, if applicable
  1211.     // and do the assignment
  1212.  
  1213.     else
  1214.     {
  1215.         Q172398(sDst);
  1216.         sDst.assign(pA);
  1217.     }
  1218. }
  1219. inline void    ssasn(std::string& sDst, const std::wstring& sSrc)
  1220. {
  1221.     if ( sSrc.empty() )
  1222.     {
  1223.         sDst.erase();
  1224.     }
  1225.     else
  1226.     {
  1227.         int nDst    = static_cast<int>(sSrc.size());
  1228.  
  1229.         // In MBCS builds, pad the buffer to account for the possibility of
  1230.         // some 3 byte characters.  Not perfect but should get most cases.
  1231.  
  1232. #ifdef SS_MBCS
  1233.         nDst    = static_cast<int>(static_cast<double>(nDst) * 1.3);
  1234. #endif
  1235.  
  1236.         sDst.resize(nDst+1);
  1237.         PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,
  1238.             sSrc.c_str(), static_cast<int>(sSrc.size()));
  1239.  
  1240.         // In MBCS builds, we don't know how long the destination string will be.
  1241.  
  1242. #ifdef SS_MBCS
  1243.         sDst.resize(sslen(szCvt));
  1244. #else
  1245.         szCvt;
  1246.         sDst.resize(sSrc.size());
  1247. #endif
  1248.     }
  1249. }
  1250. inline void    ssasn(std::string& sDst, PCWSTR pW)
  1251. {
  1252.     int nSrc    = sslen(pW);
  1253.     if ( nSrc > 0 )
  1254.     {
  1255.         int nSrc    = sslen(pW);
  1256.         int nDst    = nSrc;
  1257.  
  1258.         // In MBCS builds, pad the buffer to account for the possibility of
  1259.         // some 3 byte characters.  Not perfect but should get most cases.
  1260.  
  1261. #ifdef SS_MBCS
  1262.         nDst    = static_cast<int>(static_cast<double>(nDst) * 1.3);
  1263. #endif
  1264.  
  1265.         sDst.resize(nDst + 1);
  1266.         PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()), nDst,
  1267.             pW, nSrc);
  1268.  
  1269.         // In MBCS builds, we don't know how long the destination string will be.
  1270.  
  1271. #ifdef SS_MBCS
  1272.         sDst.resize(sslen(szCvt));
  1273. #else
  1274.         sDst.resize(nDst);
  1275.         szCvt;
  1276. #endif
  1277.     }
  1278.     else
  1279.     {
  1280.         sDst.erase();
  1281.     }
  1282. }
  1283. inline void ssasn(std::string& sDst, const int nNull)
  1284. {
  1285.     UNUSED(nNull);
  1286.     ASSERT(nNull==0);
  1287.     sDst.assign("");
  1288. }    
  1289. inline void    ssasn(std::wstring& sDst, const std::wstring& sSrc)
  1290. {
  1291.     if ( sDst.c_str() != sSrc.c_str() )
  1292.     {
  1293.         sDst.erase();
  1294.         sDst.assign(SSREF(sSrc));
  1295.     }
  1296. }
  1297. inline void    ssasn(std::wstring& sDst, PCWSTR pW)
  1298. {
  1299.     // Watch out for NULLs, as always.
  1300.  
  1301.     if ( 0 == pW )
  1302.     {
  1303.         sDst.erase();
  1304.     }
  1305.  
  1306.     // If pW actually points to part of sDst, we must NOT erase(), but
  1307.     // rather take a substring
  1308.  
  1309.     else if ( pW >= sDst.c_str() && pW <= sDst.c_str() + sDst.size() )
  1310.     {
  1311.         sDst = sDst.substr(static_cast<SW_SIZETYPE>(pW-sDst.c_str()));
  1312.     }
  1313.  
  1314.     // Otherwise (most cases) apply the assignment bug fix, if applicable
  1315.     // and do the assignment
  1316.  
  1317.     else
  1318.     {
  1319.         Q172398(sDst);
  1320.         sDst.assign(pW);
  1321.     }
  1322. }
  1323. #undef StrSizeType
  1324. inline void    ssasn(std::wstring& sDst, const std::string& sSrc)
  1325. {
  1326.     if ( sSrc.empty() )
  1327.     {
  1328.         sDst.erase();
  1329.     }
  1330.     else
  1331.     {
  1332.         int nSrc    = static_cast<int>(sSrc.size());
  1333.         int nDst    = nSrc;
  1334.  
  1335.         sDst.resize(nSrc+1);
  1336.         PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), nDst,
  1337.             sSrc.c_str(), nSrc);
  1338.  
  1339.         sDst.resize(sslen(szCvt));
  1340.     }
  1341. }
  1342. inline void    ssasn(std::wstring& sDst, PCSTR pA)
  1343. {
  1344.     int nSrc    = sslen(pA);
  1345.  
  1346.     if ( 0 == nSrc )
  1347.     {
  1348.         sDst.erase();
  1349.     }
  1350.     else
  1351.     {
  1352.         int nDst    = nSrc;
  1353.         sDst.resize(nDst+1);
  1354.         PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()), nDst, pA,
  1355.             nSrc);
  1356.  
  1357.         sDst.resize(sslen(szCvt));
  1358.     }
  1359. }
  1360. inline void ssasn(std::wstring& sDst, const int nNull)
  1361. {
  1362.     UNUSED(nNull);
  1363.     ASSERT(nNull==0);
  1364.     sDst.assign(L"");
  1365. }
  1366.  
  1367.  
  1368. // -----------------------------------------------------------------------------
  1369. // ssadd: string object concatenation -- add second argument to first
  1370. // -----------------------------------------------------------------------------
  1371. inline void    ssadd(std::string& sDst, const std::wstring& sSrc)
  1372. {
  1373.     int nSrc    = static_cast<int>(sSrc.size());
  1374.  
  1375.     if ( nSrc > 0 )
  1376.     {
  1377.         int nDst    = static_cast<int>(sDst.size());
  1378.         int nAdd    = nSrc;
  1379.  
  1380.         // In MBCS builds, pad the buffer to account for the possibility of
  1381.         // some 3 byte characters.  Not perfect but should get most cases.
  1382.  
  1383. #ifdef SS_MBCS
  1384.         nAdd        = static_cast<int>(static_cast<double>(nAdd) * 1.3);
  1385. #endif
  1386.  
  1387.         sDst.resize(nDst+nAdd+1);
  1388.         PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst),
  1389.             nAdd, sSrc.c_str(), nSrc);
  1390.  
  1391. #ifdef SS_MBCS
  1392.         sDst.resize(nDst + sslen(szCvt));
  1393. #else
  1394.         sDst.resize(nDst + nAdd);
  1395.         szCvt;
  1396. #endif
  1397.     }
  1398. }
  1399. inline void    ssadd(std::string& sDst, const std::string& sSrc)
  1400. {
  1401.     sDst += sSrc;
  1402. }
  1403. inline void    ssadd(std::string& sDst, PCWSTR pW)
  1404. {
  1405.     int nSrc        = sslen(pW);
  1406.     if ( nSrc > 0 )
  1407.     {
  1408.         int nDst    = static_cast<int>(sDst.size());
  1409.         int nAdd    = nSrc;
  1410.  
  1411. #ifdef SS_MBCS
  1412.         nAdd    = static_cast<int>(static_cast<double>(nAdd) * 1.3);
  1413. #endif
  1414.  
  1415.         sDst.resize(nDst + nAdd + 1);
  1416.         PCSTR szCvt = StdCodeCvt(const_cast<SS_PTRTYPE>(sDst.data()+nDst),
  1417.             nAdd, pW, nSrc);
  1418.  
  1419. #ifdef SS_MBCS
  1420.         sDst.resize(nDst + sslen(szCvt));
  1421. #else
  1422.         sDst.resize(nDst + nSrc);
  1423.         szCvt;
  1424. #endif
  1425.     }
  1426. }
  1427. inline void    ssadd(std::string& sDst, PCSTR pA)
  1428. {
  1429.     if ( pA )
  1430.     {
  1431.         // If the string being added is our internal string or a part of our
  1432.         // internal string, then we must NOT do any reallocation without
  1433.         // first copying that string to another object (since we're using a
  1434.         // direct pointer)
  1435.  
  1436.         if ( pA >= sDst.c_str() && pA <= sDst.c_str()+sDst.length())
  1437.         {
  1438.             if ( sDst.capacity() <= sDst.size()+sslen(pA) )
  1439.                 sDst.append(std::string(pA));
  1440.             else
  1441.                 sDst.append(pA);
  1442.         }
  1443.         else
  1444.         {
  1445.             sDst.append(pA); 
  1446.         }
  1447.     }
  1448. }
  1449. inline void    ssadd(std::wstring& sDst, const std::wstring& sSrc)
  1450. {
  1451.     sDst += sSrc;
  1452. }
  1453. inline void    ssadd(std::wstring& sDst, const std::string& sSrc)
  1454. {
  1455.     if ( !sSrc.empty() )
  1456.     {
  1457.         int nSrc    = static_cast<int>(sSrc.size());
  1458.         int nDst    = static_cast<int>(sDst.size());
  1459.  
  1460.         sDst.resize(nDst + nSrc + 1);
  1461.         PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst), 
  1462.             nSrc, sSrc.c_str(), nSrc+1);
  1463.  
  1464. #ifdef SS_MBCS
  1465.         sDst.resize(nDst + sslen(szCvt));
  1466. #else
  1467.         sDst.resize(nDst + nSrc);
  1468.         szCvt;
  1469. #endif
  1470.     }
  1471. }
  1472. inline void    ssadd(std::wstring& sDst, PCSTR pA)
  1473. {
  1474.     int nSrc        = sslen(pA);
  1475.  
  1476.     if ( nSrc > 0 )
  1477.     {
  1478.         int nDst    = static_cast<int>(sDst.size());
  1479.  
  1480.         sDst.resize(nDst + nSrc + 1);
  1481.         PCWSTR szCvt = StdCodeCvt(const_cast<SW_PTRTYPE>(sDst.data()+nDst),
  1482.             nSrc, pA, nSrc+1);
  1483.  
  1484. #ifdef SS_MBCS
  1485.         sDst.resize(nDst + sslen(szCvt));
  1486. #else
  1487.         sDst.resize(nDst + nSrc);
  1488.         szCvt;
  1489. #endif
  1490.     }
  1491. }
  1492. inline void    ssadd(std::wstring& sDst, PCWSTR pW)
  1493. {
  1494.     if ( pW )
  1495.     {
  1496.         // If the string being added is our internal string or a part of our
  1497.         // internal string, then we must NOT do any reallocation without
  1498.         // first copying that string to another object (since we're using a
  1499.         // direct pointer)
  1500.  
  1501.         if ( pW >= sDst.c_str() && pW <= sDst.c_str()+sDst.length())
  1502.         {
  1503.             if ( sDst.capacity() <= sDst.size()+sslen(pW) )
  1504.                 sDst.append(std::wstring(pW));
  1505.             else
  1506.                 sDst.append(pW);
  1507.         }
  1508.         else
  1509.         {
  1510.             sDst.append(pW);
  1511.         }
  1512.     }
  1513. }
  1514.  
  1515.  
  1516. // -----------------------------------------------------------------------------
  1517. // sscmp: comparison (case sensitive, not affected by locale)
  1518. // -----------------------------------------------------------------------------
  1519. template<typename CT>
  1520. inline int sscmp(const CT* pA1, const CT* pA2)
  1521. {
  1522.     CT f;
  1523.     CT l;
  1524.  
  1525.     do 
  1526.     {
  1527.         f = *(pA1++);
  1528.         l = *(pA2++);
  1529.     } while ( (f) && (f == l) );
  1530.  
  1531.     return (int)(f - l);
  1532. }
  1533.  
  1534. // -----------------------------------------------------------------------------
  1535. // ssicmp: comparison (case INsensitive, not affected by locale)
  1536. // -----------------------------------------------------------------------------
  1537. template<typename CT>
  1538. inline int ssicmp(const CT* pA1, const CT* pA2)
  1539. {
  1540.     // Using the "C" locale = "not affected by locale"
  1541.  
  1542.     std::locale loc = std::locale::classic();
  1543.     const std::ctype<CT>& ct = SS_USE_FACET(loc, std::ctype<CT>);
  1544.     CT f;
  1545.     CT l;
  1546.  
  1547.     do 
  1548.     {
  1549.         f = ct.tolower(*(pA1++));
  1550.         l = ct.tolower(*(pA2++));
  1551.     } while ( (f) && (f == l) );
  1552.  
  1553.     return (int)(f - l);
  1554. }
  1555.  
  1556. // -----------------------------------------------------------------------------
  1557. // ssupr/sslwr: Uppercase/Lowercase conversion functions
  1558. // -----------------------------------------------------------------------------
  1559.  
  1560. template<typename CT>
  1561. inline void sslwr(CT* pT, size_t nLen, const std::locale& loc=std::locale())
  1562. {
  1563.     SS_USE_FACET(loc, std::ctype<CT>).tolower(pT, pT+nLen);
  1564. }
  1565. template<typename CT>
  1566. inline void ssupr(CT* pT, size_t nLen, const std::locale& loc=std::locale())
  1567. {
  1568.     SS_USE_FACET(loc, std::ctype<CT>).toupper(pT, pT+nLen);
  1569. }
  1570.  
  1571. // -----------------------------------------------------------------------------
  1572. //  vsprintf/vswprintf or _vsnprintf/_vsnwprintf equivalents.  In standard
  1573. //  builds we can't use _vsnprintf/_vsnwsprintf because they're MS extensions.
  1574. // -----------------------------------------------------------------------------
  1575. #if defined(SS_ANSI) || !defined(_MSC_VER)
  1576.  
  1577.     // Borland's headers put some ANSI "C" functions in the 'std' namespace. 
  1578.     // Promote them to the global namespace so we can use them here.
  1579.  
  1580.     #if defined(__BORLANDC__)
  1581.         using std::vsprintf;
  1582.         using std::vswprintf;
  1583.     #endif
  1584.  
  1585.     inline int ssvsprintf(PSTR pA, size_t /*nCount*/, PCSTR pFmtA, va_list vl)
  1586.     {
  1587.         return vsprintf(pA, pFmtA, vl);
  1588.     }
  1589.     inline int ssvsprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
  1590.     {
  1591.         // JMO: Some distributions of the "C" have a version of vswprintf that
  1592.         // takes 3 arguments (e.g. Microsoft, Borland, GNU).  Others have a 
  1593.         // version which takes 4 arguments (an extra "count" argument in the
  1594.         // second position.  The best stab I can take at this so far is that if
  1595.         // you are NOT running with MS, Borland, or GNU, then I'll assume you
  1596.         // have the version that takes 4 arguments.
  1597.         //
  1598.         // I'm sure that these checks don't catch every platform correctly so if
  1599.         // you get compiler errors on one of the lines immediately below, it's
  1600.         // probably because your implemntation takes a different number of
  1601.         // arguments.  You can comment out the offending line (and use the
  1602.         // alternate version) or you can figure out what compiler flag to check
  1603.         // and add that preprocessor check in.  Regardless, if you get an error
  1604.         // on these lines, I'd sure like to hear from you about it.
  1605.         //
  1606.         // Thanks to Ronny Schulz for the SGI-specific checks here.
  1607.  
  1608. //    #if !defined(__MWERKS__) && !defined(__SUNPRO_CC_COMPAT) && !defined(__SUNPRO_CC)
  1609.     #if    !defined(_MSC_VER) \
  1610.         && !defined (__BORLANDC__) \
  1611.         && !defined(__GNUC__) \
  1612.         && !defined(__sgi)
  1613.  
  1614.         return vswprintf(pW, nCount, pFmtW, vl);
  1615.  
  1616.     // suddenly with the current SGI 7.3 compiler there is no such function as
  1617.     // vswprintf and the substitute needs explicit casts to compile
  1618.  
  1619.     #elif defined(__sgi)
  1620.  
  1621.         nCount;
  1622.         return vsprintf( (char *)pW, (char *)pFmtW, vl);
  1623.  
  1624.     #else
  1625.  
  1626.         nCount;
  1627.         return vswprintf(pW, pFmtW, vl);
  1628.  
  1629.     #endif
  1630.  
  1631.     }
  1632. #else
  1633.     inline int    ssnprintf(PSTR pA, size_t nCount, PCSTR pFmtA, va_list vl)
  1634.     { 
  1635.         return _vsnprintf(pA, nCount, pFmtA, vl);
  1636.     }
  1637.     inline int    ssnprintf(PWSTR pW, size_t nCount, PCWSTR pFmtW, va_list vl)
  1638.     {
  1639.         return _vsnwprintf(pW, nCount, pFmtW, vl);
  1640.     }
  1641. #endif
  1642.  
  1643.  
  1644.  
  1645. // -----------------------------------------------------------------------------
  1646. // ssload: Type safe, overloaded ::LoadString wrappers
  1647. // There is no equivalent of these in non-Win32-specific builds.  However, I'm
  1648. // thinking that with the message facet, there might eventually be one
  1649. // -----------------------------------------------------------------------------
  1650. #if defined (SS_WIN32) && !defined(SS_ANSI)
  1651.     inline int ssload(HMODULE hInst, UINT uId, PSTR pBuf, int nMax)
  1652.     {
  1653.         return ::LoadStringA(hInst, uId, pBuf, nMax);
  1654.     }
  1655.     inline int ssload(HMODULE hInst, UINT uId, PWSTR pBuf, int nMax)
  1656.     {
  1657.         return ::LoadStringW(hInst, uId, pBuf, nMax);
  1658.     }
  1659. #endif
  1660.  
  1661.  
  1662. // -----------------------------------------------------------------------------
  1663. // sscoll/ssicoll: Collation wrappers
  1664. //        Note -- with MSVC I have reversed the arguments order here because the
  1665. //        functions appear to return the opposite of what they should
  1666. // -----------------------------------------------------------------------------
  1667. template <typename CT>
  1668. inline int sscoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
  1669. {
  1670.     const std::collate<CT>& coll =
  1671.         SS_USE_FACET(std::locale(), std::collate<CT>);
  1672.  
  1673.     return coll.compare(sz2, sz2+nLen2, sz1, sz1+nLen1);
  1674. }
  1675. template <typename CT>
  1676. inline int ssicoll(const CT* sz1, int nLen1, const CT* sz2, int nLen2)
  1677. {
  1678.     const std::locale loc;
  1679.     const std::collate<CT>& coll = SS_USE_FACET(loc, std::collate<CT>);
  1680.  
  1681.     // Some implementations seem to have trouble using the collate<>
  1682.     // facet typedefs so we'll just default to basic_string and hope
  1683.     // that's what the collate facet uses (which it generally should)
  1684.  
  1685. //    std::collate<CT>::string_type s1(sz1);
  1686. //    std::collate<CT>::string_type s2(sz2);
  1687.     const std::basic_string<CT> sEmpty;
  1688.     std::basic_string<CT> s1(sz1 ? sz1 : sEmpty.c_str());
  1689.     std::basic_string<CT> s2(sz2 ? sz2 : sEmpty.c_str());
  1690.  
  1691.     sslwr(const_cast<CT*>(s1.c_str()), nLen1, loc);
  1692.     sslwr(const_cast<CT*>(s2.c_str()), nLen2, loc);
  1693.     return coll.compare(s2.c_str(), s2.c_str()+nLen2,
  1694.                         s1.c_str(), s1.c_str()+nLen1);
  1695. }
  1696.  
  1697.  
  1698.  
  1699. // -----------------------------------------------------------------------------
  1700. // ssfmtmsg: FormatMessage equivalents.  Needed because I added a CString facade
  1701. // Again -- no equivalent of these on non-Win32 builds but their might one day
  1702. // be one if the message facet gets implemented
  1703. // -----------------------------------------------------------------------------
  1704. #if defined (SS_WIN32) && !defined(SS_ANSI)
  1705.     inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
  1706.                           DWORD dwLangId, PSTR pBuf, DWORD nSize,
  1707.                           va_list* vlArgs)
  1708.     { 
  1709.         return FormatMessageA(dwFlags, pSrc, dwMsgId, dwLangId,
  1710.                               pBuf, nSize,vlArgs);
  1711.     }
  1712.     inline DWORD ssfmtmsg(DWORD dwFlags, LPCVOID pSrc, DWORD dwMsgId,
  1713.                           DWORD dwLangId, PWSTR pBuf, DWORD nSize,
  1714.                           va_list* vlArgs)
  1715.     {
  1716.         return FormatMessageW(dwFlags, pSrc, dwMsgId, dwLangId,
  1717.                               pBuf, nSize,vlArgs);
  1718.     }
  1719. #else
  1720. #endif
  1721.  
  1722.  
  1723.  
  1724. // FUNCTION: sscpy.  Copies up to 'nMax' characters from pSrc to pDst.
  1725. // -----------------------------------------------------------------------------
  1726. // FUNCTION:  sscpy
  1727. //        inline int sscpy(PSTR pDst, PCSTR pSrc, int nMax=-1);
  1728. //        inline int sscpy(PUSTR pDst,  PCSTR pSrc, int nMax=-1)
  1729. //        inline int sscpy(PSTR pDst, PCWSTR pSrc, int nMax=-1);
  1730. //        inline int sscpy(PWSTR pDst, PCWSTR pSrc, int nMax=-1);
  1731. //        inline int sscpy(PWSTR pDst, PCSTR pSrc, int nMax=-1);
  1732. //
  1733. // DESCRIPTION:
  1734. //        This function is very much (but not exactly) like strcpy.  These
  1735. //        overloads simplify copying one C-style string into another by allowing
  1736. //        the caller to specify two different types of strings if necessary.
  1737. //
  1738. //        The strings must NOT overlap
  1739. //
  1740. //        "Character" is expressed in terms of the destination string, not
  1741. //        the source.  If no 'nMax' argument is supplied, then the number of
  1742. //        characters copied will be sslen(pSrc).  A NULL terminator will
  1743. //        also be added so pDst must actually be big enough to hold nMax+1
  1744. //        characters.  The return value is the number of characters copied,
  1745. //        not including the NULL terminator.
  1746. //
  1747. // PARAMETERS: 
  1748. //        pSrc - the string to be copied FROM.  May be a char based string, an
  1749. //               MBCS string (in Win32 builds) or a wide string (wchar_t).
  1750. //        pSrc - the string to be copied TO.  Also may be either MBCS or wide
  1751. //        nMax - the maximum number of characters to be copied into szDest.  Note
  1752. //               that this is expressed in whatever a "character" means to pDst.
  1753. //               If pDst is a wchar_t type string than this will be the maximum
  1754. //               number of wchar_ts that my be copied.  The pDst string must be
  1755. //               large enough to hold least nMaxChars+1 characters.
  1756. //               If the caller supplies no argument for nMax this is a signal to
  1757. //               the routine to copy all the characters in pSrc, regardless of
  1758. //               how long it is.
  1759. //
  1760. // RETURN VALUE: none
  1761. // -----------------------------------------------------------------------------
  1762. template<typename CT1, typename CT2>
  1763. inline int sscpycvt(CT1* pDst, const CT2* pSrc, int nMax)
  1764. {
  1765.     // Note -- we assume pDst is big enough to hold pSrc.  If not, we're in
  1766.     // big trouble.  No bounds checking.  Caveat emptor.
  1767.     
  1768.     int nSrc = sslen(pSrc);
  1769.  
  1770.     const CT1* szCvt = StdCodeCvt(pDst, nMax, pSrc, nSrc);
  1771.  
  1772.     // If we're copying the same size characters, then all the "code convert"
  1773.     // just did was basically memcpy so the #of characters copied is the same
  1774.     // as the number requested.  I should probably specialize this function
  1775.     // template to achieve this purpose as it is silly to do a runtime check
  1776.     // of a fact known at compile time.  I'll get around to it.
  1777.  
  1778.     return sslen(szCvt);
  1779. }
  1780.  
  1781. inline int sscpycvt(PSTR pDst, PCSTR pSrc, int nMax)
  1782. {
  1783.     int nCount = nMax;
  1784.     for (; nCount > 0 && *pSrc; ++pSrc, ++pDst, --nCount)
  1785.         std::basic_string<char>::traits_type::assign(*pDst, *pSrc);
  1786.  
  1787.     *pDst =  '\0';
  1788.     return nMax - nCount;
  1789. }
  1790. inline int sscpycvt(PWSTR pDst, PCWSTR pSrc, int nMax)
  1791. {
  1792.     int nCount = nMax;
  1793.     for (; nCount > 0 && *pSrc; ++pSrc, ++pDst, --nCount)
  1794.         std::basic_string<wchar_t>::traits_type::assign(*pDst, *pSrc);
  1795.  
  1796.     *pDst = L'\0';
  1797.     return nMax - nCount;
  1798. }
  1799. inline int sscpycvt(PWSTR pDst, PCSTR pSrc, int nMax)
  1800. {
  1801.     // Note -- we assume pDst is big enough to hold pSrc.  If not, we're in
  1802.     // big trouble.  No bounds checking.  Caveat emptor.
  1803.  
  1804.     const PWSTR szCvt = StdCodeCvt(pDst, nMax, pSrc, nMax);
  1805.     return sslen(szCvt);
  1806. }
  1807.  
  1808. template<typename CT1, typename CT2>
  1809. inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax, int nLen)
  1810. {
  1811.     return sscpycvt(pDst, pSrc, SSMIN(nMax, nLen));
  1812. }
  1813. template<typename CT1, typename CT2>
  1814. inline int sscpy(CT1* pDst, const CT2* pSrc, int nMax)
  1815. {
  1816.     return sscpycvt(pDst, pSrc, SSMIN(nMax, sslen(pSrc)));
  1817. }
  1818. template<typename CT1, typename CT2>
  1819. inline int sscpy(CT1* pDst, const CT2* pSrc)
  1820. {
  1821.     return sscpycvt(pDst, pSrc, sslen(pSrc));
  1822. }
  1823. template<typename CT1, typename CT2>
  1824. inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc, int nMax)
  1825. {
  1826.     return sscpycvt(pDst, sSrc.c_str(), SSMIN(nMax, (int)sSrc.length()));
  1827. }
  1828. template<typename CT1, typename CT2>
  1829. inline int sscpy(CT1* pDst, const std::basic_string<CT2>& sSrc)
  1830. {
  1831.     return sscpycvt(pDst, sSrc.c_str(), (int)sSrc.length());
  1832. }
  1833.  
  1834. #ifdef SS_INC_COMDEF
  1835.     template<typename CT1>
  1836.     inline int sscpy(CT1* pDst, const _bstr_t& bs, int nMax)
  1837.     {
  1838.         return sscpycvt(pDst, static_cast<PCOLESTR>(bs),
  1839.             SSMIN(nMax, static_cast<int>(bs.length())));
  1840.     }
  1841.     template<typename CT1>
  1842.     inline int sscpy(CT1* pDst, const _bstr_t& bs)
  1843.     {
  1844.         return sscpy(pDst, bs, static_cast<int>(bs.length()));
  1845.     }
  1846. #endif
  1847.  
  1848.  
  1849. // -----------------------------------------------------------------------------
  1850. // Functional objects for changing case.  They also let you pass locales
  1851. // -----------------------------------------------------------------------------
  1852.  
  1853. template<typename CT>
  1854. struct SSToUpper : public std::binary_function<CT, std::locale, CT>
  1855. {
  1856.     inline CT operator()(const CT& t, const std::locale& loc) const
  1857.     {
  1858.         return sstoupper<CT>(t, loc);
  1859.     }
  1860. };
  1861. template<typename CT>
  1862. struct SSToLower : public std::binary_function<CT, std::locale, CT>
  1863. {
  1864.     inline CT operator()(const CT& t, const std::locale& loc) const
  1865.     {
  1866.         return sstolower<CT>(t, loc);
  1867.     }
  1868. };
  1869.  
  1870. // This struct is used for TrimRight() and TrimLeft() function implementations.
  1871. //template<typename CT>
  1872. //struct NotSpace : public std::unary_function<CT, bool>
  1873. //{
  1874. //    const std::locale& loc;
  1875. //    inline NotSpace(const std::locale& locArg) : loc(locArg) {}
  1876. //    inline bool operator() (CT t) { return !std::isspace(t, loc); }
  1877. //};
  1878. template<typename CT>
  1879. struct NotSpace : public std::unary_function<CT, bool>
  1880. {
  1881.  
  1882.     // DINKUMWARE BUG:
  1883.     // Note -- using std::isspace in a COM DLL gives us access violations
  1884.     // because it causes the dynamic addition of a function to be called
  1885.     // when the library shuts down.  Unfortunately the list is maintained
  1886.     // in DLL memory but the function is in static memory.  So the COM DLL
  1887.     // goes away along with the function that was supposed to be called,
  1888.     // and then later when the DLL CRT shuts down it unloads the list and
  1889.     // tries to call the long-gone function.
  1890.     // This is DinkumWare's implementation problem.  If you encounter this
  1891.     // problem, you may replace the calls here with good old isspace() and
  1892.     // iswspace() from the CRT unless they specify SS_ANSI
  1893.     
  1894.     const std::locale loc;
  1895.     NotSpace(const std::locale& locArg=std::locale()) : loc(locArg) {}
  1896.     bool operator() (CT t) const { return !std::isspace(t, loc); }
  1897. };
  1898.  
  1899.  
  1900.  
  1901.  
  1902. //            Now we can define the template (finally!)
  1903. // =============================================================================
  1904. // TEMPLATE: CStdStr
  1905. //        template<typename CT> class CStdStr : public std::basic_string<CT>
  1906. //
  1907. // REMARKS:
  1908. //        This template derives from basic_string<CT> and adds some MFC CString-
  1909. //        like functionality
  1910. //
  1911. //        Basically, this is my attempt to make Standard C++ library strings as
  1912. //        easy to use as the MFC CString class.
  1913. //
  1914. //        Note that although this is a template, it makes the assumption that the
  1915. //        template argument (CT, the character type) is either char or wchar_t.  
  1916. // =============================================================================
  1917.  
  1918. //#define CStdStr _SS    // avoid compiler warning 4786
  1919.  
  1920. //    template<typename ARG> ARG& FmtArg(ARG& arg)  { return arg; }
  1921. //    PCSTR  FmtArg(const std::string& arg)  { return arg.c_str(); }
  1922. //    PCWSTR FmtArg(const std::wstring& arg) { return arg.c_str(); }
  1923.  
  1924. template<typename ARG>
  1925. struct FmtArg
  1926. {
  1927.     explicit FmtArg(const ARG& arg) : a_(arg) {}
  1928.     const ARG& operator()() const { return a_; }
  1929.     const ARG& a_;
  1930. private:
  1931.     FmtArg& operator=(const FmtArg&) { return *this; }
  1932. };
  1933.  
  1934. template<typename CT>
  1935. class CStdStr : public std::basic_string<CT>
  1936. {
  1937.     // Typedefs for shorter names.  Using these names also appears to help
  1938.     // us avoid some ambiguities that otherwise arise on some platforms
  1939.  
  1940.     #define MYBASE std::basic_string<CT>                 // my base class
  1941.     //typedef typename std::basic_string<CT>        MYBASE;     // my base class
  1942.     typedef CStdStr<CT>                            MYTYPE;     // myself
  1943.     typedef typename MYBASE::const_pointer        PCMYSTR; // PCSTR or PCWSTR 
  1944.     typedef typename MYBASE::pointer            PMYSTR;     // PSTR or PWSTR
  1945.     typedef typename MYBASE::iterator            MYITER;  // my iterator type
  1946.     typedef typename MYBASE::const_iterator        MYCITER; // you get the idea...
  1947.     typedef typename MYBASE::reverse_iterator    MYRITER;
  1948.     typedef typename MYBASE::size_type            MYSIZE;   
  1949.     typedef typename MYBASE::value_type            MYVAL; 
  1950.     typedef typename MYBASE::allocator_type        MYALLOC;
  1951.     
  1952. public:
  1953.     // shorthand conversion from PCTSTR to string resource ID
  1954.     #define SSRES(pctstr)  LOWORD(reinterpret_cast<unsigned long>(pctstr))    
  1955.  
  1956.     bool TryLoad(const void* pT)
  1957.     {
  1958.         bool bLoaded = false;
  1959.  
  1960. #if defined(SS_WIN32) && !defined(SS_ANSI)
  1961.         if ( ( pT != NULL ) && SS_IS_INTRESOURCE(pT) )
  1962.         {
  1963.             UINT nId = LOWORD(reinterpret_cast<unsigned long>(pT));
  1964.             if ( !LoadString(nId) )
  1965.             {
  1966.                 TRACE(_T("Can't load string %u\n"), SSRES(pT));
  1967.             }
  1968.             bLoaded = true;
  1969.         }
  1970. #endif
  1971.  
  1972.         return bLoaded;
  1973.     }
  1974.  
  1975.  
  1976.     // CStdStr inline constructors
  1977.     CStdStr()
  1978.     {
  1979.     }
  1980.  
  1981.     CStdStr(const MYTYPE& str) : MYBASE(SSREF(str))
  1982.     {
  1983.     }
  1984.  
  1985.     CStdStr(const std::string& str)
  1986.     {
  1987.         ssasn(*this, SSREF(str));
  1988.     }
  1989.  
  1990.     CStdStr(const std::wstring& str)
  1991.     {
  1992.         ssasn(*this, SSREF(str));
  1993.     }
  1994.  
  1995.     CStdStr(PCMYSTR pT, MYSIZE n) : MYBASE(pT, n)
  1996.     {
  1997.     }
  1998.  
  1999. #ifdef SS_UNSIGNED
  2000.     CStdStr(PCUSTR pU)
  2001.     {
  2002.         *this = reinterpret_cast<PCSTR>(pU);
  2003.     }
  2004. #endif
  2005.  
  2006.     CStdStr(PCSTR pA)
  2007.     {
  2008.     #ifdef SS_ANSI
  2009.         *this = pA;
  2010.     #else
  2011.         if ( !TryLoad(pA) )
  2012.             *this = pA;
  2013.     #endif
  2014.     }
  2015.  
  2016.     CStdStr(PCWSTR pW)
  2017.     {
  2018.     #ifdef SS_ANSI
  2019.         *this = pW;
  2020.     #else
  2021.         if ( !TryLoad(pW) )
  2022.             *this = pW;
  2023.     #endif
  2024.     }
  2025.  
  2026.     CStdStr(MYCITER first, MYCITER last)
  2027.         : MYBASE(first, last)
  2028.     {
  2029.     }
  2030.  
  2031.     CStdStr(MYSIZE nSize, MYVAL ch, const MYALLOC& al=MYALLOC())
  2032.         : MYBASE(nSize, ch, al)
  2033.     {
  2034.     }
  2035.  
  2036.     #ifdef SS_INC_COMDEF
  2037.         CStdStr(const _bstr_t& bstr)
  2038.         {
  2039.             if ( bstr.length() > 0 )
  2040.                 this->append(static_cast<PCMYSTR>(bstr), bstr.length());
  2041.         }
  2042.     #endif
  2043.  
  2044.     // CStdStr inline assignment operators -- the ssasn function now takes care
  2045.     // of fixing  the MSVC assignment bug (see knowledge base article Q172398).
  2046.     MYTYPE& operator=(const MYTYPE& str)
  2047.     { 
  2048.         ssasn(*this, str); 
  2049.         return *this;
  2050.     }
  2051.  
  2052.     MYTYPE& operator=(const std::string& str)
  2053.     {
  2054.         ssasn(*this, str);
  2055.         return *this;
  2056.     }
  2057.  
  2058.     MYTYPE& operator=(const std::wstring& str)
  2059.     {
  2060.         ssasn(*this, str);
  2061.         return *this;
  2062.     }
  2063.  
  2064.     MYTYPE& operator=(PCSTR pA)
  2065.     {
  2066.         ssasn(*this, pA);
  2067.         return *this;
  2068.     }
  2069.  
  2070.     MYTYPE& operator=(PCWSTR pW)
  2071.     {
  2072.         ssasn(*this, pW);
  2073.         return *this;
  2074.     }
  2075.  
  2076. #ifdef SS_UNSIGNED
  2077.     MYTYPE& operator=(PCUSTR pU)
  2078.     {
  2079.         ssasn(*this, reinterpret_cast<PCSTR>(pU));
  2080.         return *this;
  2081.     }
  2082. #endif
  2083.  
  2084.     MYTYPE& operator=(CT t)
  2085.     {
  2086.         Q172398(*this);
  2087.         this->assign(1, t);
  2088.         return *this;
  2089.     }
  2090.  
  2091.     #ifdef SS_INC_COMDEF
  2092.         MYTYPE& operator=(const _bstr_t& bstr)
  2093.         {
  2094.             if ( bstr.length() > 0 )
  2095.             {
  2096.                 this->assign(static_cast<PCMYSTR>(bstr), bstr.length());
  2097.                 return *this;
  2098.             }
  2099.             else
  2100.             {
  2101.                 this->erase();
  2102.                 return *this;
  2103.             }
  2104.         }
  2105.     #endif
  2106.  
  2107.  
  2108.     // Overloads  also needed to fix the MSVC assignment bug (KB: Q172398)
  2109.     //  *** Thanks to Pete The Plumber for catching this one ***
  2110.     // They also are compiled if you have explicitly turned off refcounting
  2111.     #if ( defined(_MSC_VER) && ( _MSC_VER < 1200 ) ) || defined(SS_NO_REFCOUNT) 
  2112.  
  2113.         MYTYPE& assign(const MYTYPE& str)
  2114.         {
  2115.             Q172398(*this);
  2116.             sscpy(GetBuffer(str.size()+1), SSREF(str));
  2117.             this->ReleaseBuffer(str.size());
  2118.             return *this;
  2119.         }
  2120.  
  2121.         MYTYPE& assign(const MYTYPE& str, MYSIZE nStart, MYSIZE nChars)
  2122.         {
  2123.             // This overload of basic_string::assign is supposed to assign up to
  2124.             // <nChars> or the NULL terminator, whichever comes first.  Since we
  2125.             // are about to call a less forgiving overload (in which <nChars>
  2126.             // must be a valid length), we must adjust the length here to a safe
  2127.             // value.  Thanks to Ullrich PollΣhne for catching this bug
  2128.  
  2129.             nChars        = SSMIN(nChars, str.length() - nStart);
  2130.             MYTYPE strTemp(str.c_str()+nStart, nChars);
  2131.             Q172398(*this);
  2132.             this->assign(strTemp);
  2133.             return *this;
  2134.         }
  2135.  
  2136.         MYTYPE& assign(const MYBASE& str)
  2137.         {
  2138.             ssasn(*this, str);
  2139.             return *this;
  2140.         }
  2141.  
  2142.         MYTYPE& assign(const MYBASE& str, MYSIZE nStart, MYSIZE nChars)
  2143.         {
  2144.             // This overload of basic_string::assign is supposed to assign up to
  2145.             // <nChars> or the NULL terminator, whichever comes first.  Since we
  2146.             // are about to call a less forgiving overload (in which <nChars>
  2147.             // must be a valid length), we must adjust the length here to a safe
  2148.             // value. Thanks to Ullrich PollΣhne for catching this bug
  2149.  
  2150.             nChars        = SSMIN(nChars, str.length() - nStart);
  2151.  
  2152.             // Watch out for assignment to self
  2153.  
  2154.             if ( this == &str )
  2155.             {
  2156.                 MYTYPE strTemp(str.c_str() + nStart, nChars);
  2157.                 static_cast<MYBASE*>(this)->assign(strTemp);
  2158.             }
  2159.             else
  2160.             {
  2161.                 Q172398(*this);
  2162.                 static_cast<MYBASE*>(this)->assign(str.c_str()+nStart, nChars);
  2163.             }
  2164.             return *this;
  2165.         }
  2166.  
  2167.         MYTYPE& assign(const CT* pC, MYSIZE nChars)
  2168.         {
  2169.             // Q172398 only fix -- erase before assigning, but not if we're
  2170.             // assigning from our own buffer
  2171.  
  2172.     #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 )
  2173.             if ( !this->empty() &&
  2174.                 ( pC < this->data() || pC > this->data() + this->capacity() ) )
  2175.             {
  2176.                 this->erase();
  2177.             }
  2178.     #endif
  2179.             Q172398(*this);
  2180.             static_cast<MYBASE*>(this)->assign(pC, nChars);
  2181.             return *this;
  2182.         }
  2183.  
  2184.         MYTYPE& assign(MYSIZE nChars, MYVAL val)
  2185.         {
  2186.             Q172398(*this);
  2187.             static_cast<MYBASE*>(this)->assign(nChars, val);
  2188.             return *this;
  2189.         }
  2190.  
  2191.         MYTYPE& assign(const CT* pT)
  2192.         {
  2193.             return this->assign(pT, MYBASE::traits_type::length(pT));
  2194.         }
  2195.  
  2196.         MYTYPE& assign(MYCITER iterFirst, MYCITER iterLast)
  2197.         {
  2198.     #if defined ( _MSC_VER ) && ( _MSC_VER < 1200 ) 
  2199.             // Q172398 fix.  don't call erase() if we're assigning from ourself
  2200.             if ( iterFirst < this->begin() ||
  2201.                  iterFirst > this->begin() + this->size() )
  2202.             {
  2203.                 this->erase()
  2204.             }
  2205.     #endif
  2206.             this->replace(this->begin(), this->end(), iterFirst, iterLast);
  2207.             return *this;
  2208.         }
  2209.     #endif
  2210.  
  2211.  
  2212.     // -------------------------------------------------------------------------
  2213.     // CStdStr inline concatenation.
  2214.     // -------------------------------------------------------------------------
  2215.     MYTYPE& operator+=(const MYTYPE& str)
  2216.     {
  2217.         ssadd(*this, str);
  2218.         return *this;
  2219.     }
  2220.  
  2221.     MYTYPE& operator+=(const std::string& str)
  2222.     {
  2223.         ssadd(*this, str);
  2224.         return *this; 
  2225.     }
  2226.  
  2227.     MYTYPE& operator+=(const std::wstring& str)
  2228.     {
  2229.         ssadd(*this, str);
  2230.         return *this;
  2231.     }
  2232.  
  2233.     MYTYPE& operator+=(PCSTR pA)
  2234.     {
  2235.         ssadd(*this, pA);
  2236.         return *this;
  2237.     }
  2238.  
  2239.     MYTYPE& operator+=(PCWSTR pW)
  2240.     {
  2241.         ssadd(*this, pW);
  2242.         return *this;
  2243.     }
  2244.  
  2245.     MYTYPE& operator+=(CT t)
  2246.     {
  2247.         this->append(1, t);
  2248.         return *this;
  2249.     }
  2250.     #ifdef SS_INC_COMDEF    // if we have _bstr_t, define a += for it too.
  2251.         MYTYPE& operator+=(const _bstr_t& bstr)
  2252.         {
  2253.             return this->operator+=(static_cast<PCMYSTR>(bstr));
  2254.         }
  2255.     #endif
  2256.  
  2257.  
  2258.     // -------------------------------------------------------------------------
  2259.     // Case changing functions
  2260.     // -------------------------------------------------------------------------
  2261.  
  2262.     MYTYPE& ToUpper(const std::locale& loc=std::locale())
  2263.     {
  2264.         // Note -- if there are any MBCS character sets in which the lowercase
  2265.         // form a character takes up a different number of bytes than the
  2266.         // uppercase form, this would probably not work...
  2267.  
  2268.         std::transform(this->begin(),
  2269.                        this->end(),
  2270.                        this->begin(),
  2271.                        std::bind2nd(SSToUpper<CT>(), loc));
  2272.  
  2273.         // ...but if it were, this would probably work better.  Also, this way
  2274.         // seems to be a bit faster when anything other then the "C" locale is
  2275.         // used...
  2276.  
  2277. //        if ( !empty() )
  2278. //        {
  2279. //            ssupr(this->GetBuf(), this->size(), loc);
  2280. //            this->RelBuf();
  2281. //        }
  2282.  
  2283.         return *this;
  2284.     }
  2285.  
  2286.     MYTYPE& ToLower(const std::locale& loc=std::locale())
  2287.     {
  2288.         // Note -- if there are any MBCS character sets in which the lowercase
  2289.         // form a character takes up a different number of bytes than the
  2290.         // uppercase form, this would probably not work...
  2291.  
  2292.         std::transform(this->begin(),
  2293.                        this->end(),
  2294.                        this->begin(),
  2295.                        std::bind2nd(SSToLower<CT>(), loc));
  2296.  
  2297.         // ...but if it were, this would probably work better.  Also, this way
  2298.         // seems to be a bit faster when anything other then the "C" locale is
  2299.         // used...
  2300.  
  2301. //        if ( !empty() )
  2302. //        {
  2303. //            sslwr(this->GetBuf(), this->size(), loc);
  2304. //            this->RelBuf();
  2305. //        }
  2306.         return *this;
  2307.     }
  2308.  
  2309.  
  2310.     MYTYPE& Normalize()
  2311.     {
  2312.         return Trim().ToLower();
  2313.     }
  2314.  
  2315.  
  2316.     // -------------------------------------------------------------------------
  2317.     // CStdStr -- Direct access to character buffer.  In the MS' implementation,
  2318.     // the at() function that we use here also calls _Freeze() providing us some
  2319.     // protection from multithreading problems associated with ref-counting.
  2320.     // In VC 7 and later, of course, the ref-counting stuff is gone.
  2321.     // -------------------------------------------------------------------------
  2322.  
  2323.     CT* GetBuf(int nMinLen=-1)
  2324.     {
  2325.         if ( static_cast<int>(size()) < nMinLen )
  2326.             this->resize(static_cast<MYSIZE>(nMinLen));
  2327.  
  2328.         return this->empty() ? const_cast<CT*>(this->data()) : &(this->at(0));
  2329.     }
  2330.  
  2331.     CT* SetBuf(int nLen)
  2332.     {
  2333.         nLen = ( nLen > 0 ? nLen : 0 );
  2334.         if ( this->capacity() < 1 && nLen == 0 )
  2335.             this->resize(1);
  2336.  
  2337.         this->resize(static_cast<MYSIZE>(nLen));
  2338.         return const_cast<CT*>(this->data());
  2339.     }
  2340.     void RelBuf(int nNewLen=-1)
  2341.     {
  2342.         this->resize(static_cast<MYSIZE>(nNewLen > -1 ? nNewLen :
  2343.                                                         sslen(this->c_str())));
  2344.     }
  2345.  
  2346.     void BufferRel()         { RelBuf(); }            // backwards compatability
  2347.     CT*  Buffer()             { return GetBuf(); }    // backwards compatability
  2348.     CT*  BufferSet(int nLen) { return SetBuf(nLen);}// backwards compatability
  2349.  
  2350.     bool Equals(const CT* pT, bool bUseCase=false) const
  2351.     {
  2352.         return  0 == (bUseCase ? this->compare(pT) : ssicmp(this->c_str(), pT));
  2353.     } 
  2354.  
  2355.     // -------------------------------------------------------------------------
  2356.     // FUNCTION:  CStdStr::Load
  2357.     // REMARKS:
  2358.     //        Loads string from resource specified by nID
  2359.     //
  2360.     // PARAMETERS:
  2361.     //        nID - resource Identifier.  Purely a Win32 thing in this case
  2362.     //
  2363.     // RETURN VALUE:
  2364.     //        true if successful, false otherwise
  2365.     // -------------------------------------------------------------------------
  2366.  
  2367. #ifndef SS_ANSI
  2368.  
  2369.     bool Load(UINT nId, HMODULE hModule=NULL)
  2370.     {
  2371.         bool bLoaded        = false;    // set to true of we succeed.
  2372.  
  2373.     #ifdef _MFC_VER        // When in Rome (or MFC land)...
  2374.  
  2375.         // If they gave a resource handle, use it.  Note - this is archaic
  2376.         // and not really what I would recommend.  But then again, in MFC
  2377.         // land, you ought to be using CString for resources anyway since
  2378.         // it walks the resource chain for you.
  2379.  
  2380.         HMODULE hModuleOld = NULL;
  2381.  
  2382.         if ( NULL != hModule )
  2383.         {
  2384.             hModuleOld = AfxGetResourceHandle();
  2385.             AfxSetResourceHandle(hModule);
  2386.         }
  2387.  
  2388.         // ...load the string
  2389.  
  2390.         CString strRes;
  2391.         bLoaded                = FALSE != strRes.LoadString(nId);
  2392.  
  2393.         // ...and if we set the resource handle, restore it.
  2394.  
  2395.         if ( NULL != hModuleOld )
  2396.             AfxSetResourceHandle(hModule);
  2397.  
  2398.         if ( bLoaded )
  2399.             *this            = strRes;
  2400.  
  2401.     #else // otherwise make our own hackneyed version of CString's Load
  2402.         
  2403.         // Get the resource name and module handle
  2404.  
  2405.         if ( NULL == hModule )
  2406.             hModule            = GetResourceHandle();
  2407.  
  2408.         PCTSTR szName        = MAKEINTRESOURCE((nId>>4)+1); // lifted 
  2409.         DWORD dwSize        = 0;
  2410.  
  2411.         // No sense continuing if we can't find the resource
  2412.  
  2413.         HRSRC hrsrc            = ::FindResource(hModule, szName, RT_STRING);
  2414.  
  2415.         if ( NULL == hrsrc )
  2416.         {
  2417.             TRACE(_T("Cannot find resource %d: 0x%X"), nId, ::GetLastError());
  2418.         }
  2419.         else if ( 0 == (dwSize = ::SizeofResource(hModule, hrsrc) / sizeof(CT)))
  2420.         {
  2421.             TRACE(_T("Cant get size of resource %d 0x%X\n"),nId,GetLastError());
  2422.         }
  2423.         else
  2424.         {
  2425.             bLoaded            = 0 != ssload(hModule, nId, GetBuf(dwSize), dwSize);
  2426.             ReleaseBuffer();
  2427.         }
  2428.  
  2429.     #endif  // #ifdef _MFC_VER
  2430.  
  2431.         if ( !bLoaded )
  2432.             TRACE(_T("String not loaded 0x%X\n"), ::GetLastError());
  2433.  
  2434.         return bLoaded;
  2435.     }
  2436.  
  2437. #endif  // #ifdef SS_ANSI
  2438.     
  2439.     // -------------------------------------------------------------------------
  2440.     // FUNCTION:  CStdStr::Format
  2441.     //        void _cdecl Formst(CStdStringA& PCSTR szFormat, ...)
  2442.     //        void _cdecl Format(PCSTR szFormat);
  2443.     //           
  2444.     // DESCRIPTION:
  2445.     //        This function does sprintf/wsprintf style formatting on CStdStringA
  2446.     //        objects.  It looks a lot like MFC's CString::Format.  Some people
  2447.     //        might even call this identical.  Fortunately, these people are now
  2448.     //        dead... heh heh.
  2449.     //
  2450.     // PARAMETERS: 
  2451.     //        nId - ID of string resource holding the format string
  2452.     //        szFormat - a PCSTR holding the format specifiers
  2453.     //        argList - a va_list holding the arguments for the format specifiers.
  2454.     //
  2455.     // RETURN VALUE:  None.
  2456.     // -------------------------------------------------------------------------
  2457.     // formatting (using wsprintf style formatting)
  2458.  
  2459.     // If they want a Format() function that safely handles string objects
  2460.     // without casting
  2461.  
  2462. #ifdef SS_SAFE_FORMAT       
  2463.     
  2464.     // Question:  Joe, you wacky coder you, why do you have so many overloads
  2465.     //      of the Format() function
  2466.     // Answer:  One reason only - CString compatability.  In short, by making
  2467.     //      the Format() function a template this way, I can do strong typing
  2468.     //      and allow people to pass CStdString arguments as fillers for
  2469.     //      "%s" format specifiers without crashing their program!  The downside
  2470.     //      is that I need to overload on the number of arguments.   If you are
  2471.     //      passing more arguments than I have listed below in any of my
  2472.     //      overloads, just add another one.
  2473.     //
  2474.     //      Yes, yes, this is really ugly.  In essence what I am doing here is
  2475.     //      protecting people from a bad (and incorrect) programming practice
  2476.     //      that they should not be doing anyway.  I am protecting them from
  2477.     //      themselves.  Why am I doing this?  Well, if you had any idea the
  2478.     //      number of times I've been emailed by people about this
  2479.     //      "incompatability" in my code, you wouldn't ask.
  2480.  
  2481.     void Fmt(const CT* szFmt, ...)
  2482.     {
  2483.         va_list argList;
  2484.         va_start(argList, szFmt);
  2485.         FormatV(szFmt, argList);
  2486.         va_end(argList);
  2487.     }
  2488.  
  2489. #ifndef SS_ANSI
  2490.  
  2491.     void Format(UINT nId)
  2492.     {
  2493.         MYTYPE strFmt;
  2494.         if ( strFmt.Load(nId) ) 
  2495.             this->swap(strFmt);
  2496.     }
  2497.     template<class A1>
  2498.     void Format(UINT nId, const A1& v)
  2499.     {
  2500.         MYTYPE strFmt;
  2501.         if ( strFmt.Load(nId) )
  2502.             Fmt(strFmt, FmtArg<A1>(v)());
  2503.     }
  2504.     template<class A1, class A2>
  2505.     void Format(UINT nId, const A1& v1, const A2& v2)
  2506.     {
  2507.         MYTYPE strFmt;
  2508.         if ( strFmt.Load(nId) )
  2509.            Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)());
  2510.     }
  2511.     template<class A1, class A2, class A3>
  2512.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3)
  2513.     {
  2514.         MYTYPE strFmt;
  2515.         if ( strFmt.Load(nId) )
  2516.         {
  2517.             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2518.             FmtArg<A3>(v3)());
  2519.         }
  2520.     }
  2521.     template<class A1, class A2, class A3, class A4>
  2522.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
  2523.                 const A4& v4)
  2524.     {
  2525.         MYTYPE strFmt;
  2526.         if ( strFmt.Load(nId) )
  2527.         {
  2528.             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2529.                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)());
  2530.         }
  2531.     }
  2532.     template<class A1, class A2, class A3, class A4, class A5>
  2533.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
  2534.                 const A4& v4, const A5& v5)
  2535.     {
  2536.         MYTYPE strFmt;
  2537.         if ( strFmt.Load(nId) )
  2538.         {
  2539.             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2540.                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)());
  2541.         }
  2542.     }
  2543.     template<class A1, class A2, class A3, class A4, class A5, class A6>
  2544.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
  2545.                 const A4& v4, const A5& v5, const A6& v6)
  2546.     {
  2547.         MYTYPE strFmt;
  2548.         if ( strFmt.Load(nId) )
  2549.         {
  2550.             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2551.                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(),FmtArg<A5>(v5)(),
  2552.                 FmtArg<A6>(v6)());
  2553.         }
  2554.     }
  2555.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2556.         class A7>
  2557.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
  2558.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7)
  2559.     {
  2560.         MYTYPE strFmt;
  2561.         if ( strFmt.Load(nId) )
  2562.         {
  2563.             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2564.                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(),FmtArg<A5>(v5)(),
  2565.                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)());
  2566.         }
  2567.     }
  2568.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2569.         class A7, class A8>
  2570.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
  2571.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2572.                 const A8& v8)
  2573.     {
  2574.         MYTYPE strFmt;
  2575.         if ( strFmt.Load(nId) )
  2576.         {
  2577.            Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2578.                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2579.                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)());
  2580.         }
  2581.     }
  2582.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2583.         class A7, class A8, class A9>
  2584.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
  2585.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2586.                 const A8& v8, const A9& v9)
  2587.     {
  2588.         MYTYPE strFmt;
  2589.         if ( strFmt.Load(nId) )
  2590.         {
  2591.             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2592.                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2593.                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2594.                 FmtArg<A9>(v9)());
  2595.         }
  2596.     }
  2597.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2598.         class A7, class A8, class A9, class A10>
  2599.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
  2600.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2601.                 const A8& v8, const A9& v9, const A10& v10)
  2602.     {
  2603.         MYTYPE strFmt;
  2604.         if ( strFmt.Load(nId) )
  2605.         {
  2606.             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2607.                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2608.                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2609.                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)());
  2610.         }
  2611.     }
  2612.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2613.         class A7, class A8, class A9, class A10, class A11>
  2614.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
  2615.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2616.                 const A8& v8, const A9& v9, const A10& v10, const A11& v11)
  2617.     {
  2618.         MYTYPE strFmt;
  2619.         if ( strFmt.Load(nId) )
  2620.         {
  2621.             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2622.                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2623.                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2624.                 FmtArg<A9>(v9)(),FmtArg<A10>(v10)(),FmtArg<A11>(v11)());
  2625.         }
  2626.     }
  2627.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2628.         class A7, class A8, class A9, class A10, class A11, class A12>
  2629.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
  2630.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2631.                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
  2632.                 const A12& v12)
  2633.     {
  2634.         MYTYPE strFmt;
  2635.         if ( strFmt.Load(nId) )
  2636.         {
  2637.             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2638.                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2639.                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2640.                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
  2641.                 FmtArg<A12>(v12)());
  2642.         }
  2643.     }
  2644.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2645.         class A7, class A8, class A9, class A10, class A11, class A12,
  2646.         class A13>
  2647.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
  2648.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2649.                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
  2650.                 const A12& v12, const A13& v13)
  2651.     {
  2652.         MYTYPE strFmt;
  2653.         if ( strFmt.Load(nId) )
  2654.         {
  2655.             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2656.                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2657.                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2658.                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
  2659.                 FmtArg<A12>(v12)(), FmtArg<A13>(v13)());
  2660.         }
  2661.     }
  2662.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2663.         class A7, class A8, class A9, class A10, class A11, class A12,
  2664.         class A13, class A14>
  2665.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
  2666.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2667.                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
  2668.                 const A12& v12, const A13& v13, const A14& v14)
  2669.     {
  2670.         MYTYPE strFmt;
  2671.         if ( strFmt.Load(nId) )
  2672.         {
  2673.             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2674.                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2675.                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2676.                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
  2677.                 FmtArg<A12>(v12)(), FmtArg<A13>(v13)(),FmtArg<A14>(v14)());
  2678.         }
  2679.     }
  2680.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2681.         class A7, class A8, class A9, class A10, class A11, class A12,
  2682.         class A13, class A14, class A15>
  2683.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
  2684.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2685.                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
  2686.                 const A12& v12, const A13& v13, const A14& v14, const A15& v15)
  2687.     {
  2688.         MYTYPE strFmt;
  2689.         if ( strFmt.Load(nId) )
  2690.         {
  2691.             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2692.                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2693.                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2694.                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
  2695.                 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
  2696.                 FmtArg<A15>(v15)());
  2697.         }
  2698.     }
  2699.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2700.         class A7, class A8, class A9, class A10, class A11, class A12,
  2701.         class A13, class A14, class A15, class A16>
  2702.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
  2703.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2704.                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
  2705.                 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
  2706.                 const A16& v16)
  2707.     {
  2708.         MYTYPE strFmt;
  2709.         if ( strFmt.Load(nId) )
  2710.         {
  2711.             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2712.                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2713.                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2714.                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
  2715.                 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
  2716.                 FmtArg<A15>(v15)(), FmtArg<A16>(v16)());
  2717.         }
  2718.     }
  2719.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2720.         class A7, class A8, class A9, class A10, class A11, class A12,
  2721.         class A13, class A14, class A15, class A16, class A17>
  2722.     void Format(UINT nId, const A1& v1, const A2& v2, const A3& v3,
  2723.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2724.                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
  2725.                 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
  2726.                 const A16& v16, const A17& v17)
  2727.     {
  2728.         MYTYPE strFmt;
  2729.         if ( strFmt.Load(nId) )
  2730.         {
  2731.             Fmt(strFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2732.                 FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2733.                 FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2734.                 FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
  2735.                 FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
  2736.                 FmtArg<A15>(v15)(),FmtArg<A16>(v16)(),FmtArg<A17>(v17)());
  2737.         }
  2738.     }
  2739.     
  2740. #endif // #ifndef SS_ANSI
  2741.  
  2742.     // ...now the other overload of Format: the one that takes a string literal
  2743.  
  2744.     void Format(const CT* szFmt)
  2745.     {
  2746.         *this = szFmt;
  2747.     }
  2748.     template<class A1>
  2749.     void Format(const CT* szFmt, A1 v)
  2750.     {
  2751.         Fmt(szFmt, FmtArg<A1>(v)());
  2752.     }
  2753.     template<class A1, class A2>
  2754.     void Format(const CT* szFmt, const A1& v1, const A2& v2)
  2755.     {
  2756.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)());
  2757.     }
  2758.     template<class A1, class A2, class A3>
  2759.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3)
  2760.     {
  2761.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2762.             FmtArg<A3>(v3)());
  2763.     }
  2764.     template<class A1, class A2, class A3, class A4>
  2765.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
  2766.                 const A4& v4)
  2767.     {
  2768.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2769.             FmtArg<A3>(v3)(), FmtArg<A4>(v4)());
  2770.     }
  2771.     template<class A1, class A2, class A3, class A4, class A5>
  2772.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
  2773.                 const A4& v4, const A5& v5)
  2774.     {
  2775.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2776.             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)());
  2777.     }
  2778.     template<class A1, class A2, class A3, class A4, class A5, class A6>
  2779.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
  2780.                 const A4& v4, const A5& v5, const A6& v6)
  2781.     {
  2782.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2783.             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2784.             FmtArg<A6>(v6)());
  2785.     }
  2786.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2787.         class A7>
  2788.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
  2789.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7)
  2790.     {
  2791.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2792.             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2793.             FmtArg<A6>(v6)(), FmtArg<A7>(v7)());
  2794.     }
  2795.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2796.         class A7, class A8>
  2797.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
  2798.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2799.                 const A8& v8)
  2800.     {
  2801.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2802.             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2803.             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)());
  2804.     }
  2805.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2806.         class A7, class A8, class A9>
  2807.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
  2808.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2809.                 const A8& v8, const A9& v9)
  2810.     {
  2811.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2812.             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2813.             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2814.             FmtArg<A9>(v9)());
  2815.     }
  2816.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2817.         class A7, class A8, class A9, class A10>
  2818.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
  2819.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2820.                 const A8& v8, const A9& v9, const A10& v10)
  2821.     {
  2822.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2823.             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2824.             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2825.             FmtArg<A9>(v9)(), FmtArg<A10>(v10)());
  2826.     }
  2827.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2828.         class A7, class A8, class A9, class A10, class A11>
  2829.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
  2830.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2831.                 const A8& v8, const A9& v9, const A10& v10, const A11& v11)
  2832.     {
  2833.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2834.             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2835.             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2836.             FmtArg<A9>(v9)(),FmtArg<A10>(v10)(),FmtArg<A11>(v11)());
  2837.     }
  2838.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2839.         class A7, class A8, class A9, class A10, class A11, class A12>
  2840.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
  2841.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2842.                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
  2843.                 const A12& v12)
  2844.     {
  2845.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2846.             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2847.             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2848.             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
  2849.             FmtArg<A12>(v12)());
  2850.     }
  2851.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2852.         class A7, class A8, class A9, class A10, class A11, class A12,
  2853.         class A13>
  2854.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
  2855.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2856.                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
  2857.                 const A12& v12, const A13& v13)
  2858.     {
  2859.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2860.             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2861.             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2862.             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
  2863.             FmtArg<A12>(v12)(), FmtArg<A13>(v13)());
  2864.     }
  2865.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2866.         class A7, class A8, class A9, class A10, class A11, class A12,
  2867.         class A13, class A14>
  2868.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
  2869.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2870.                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
  2871.                 const A12& v12, const A13& v13, const A14& v14)
  2872.     {
  2873.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2874.             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2875.             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2876.             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
  2877.             FmtArg<A12>(v12)(), FmtArg<A13>(v13)(),FmtArg<A14>(v14)());
  2878.     }
  2879.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2880.         class A7, class A8, class A9, class A10, class A11, class A12,
  2881.         class A13, class A14, class A15>
  2882.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
  2883.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2884.                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
  2885.                 const A12& v12, const A13& v13, const A14& v14, const A15& v15)
  2886.     {
  2887.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2888.             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2889.             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2890.             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
  2891.             FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
  2892.             FmtArg<A15>(v15)());
  2893.     }
  2894.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2895.         class A7, class A8, class A9, class A10, class A11, class A12,
  2896.         class A13, class A14, class A15, class A16>
  2897.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
  2898.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2899.                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
  2900.                 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
  2901.                 const A16& v16)
  2902.     {
  2903.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2904.             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2905.             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2906.             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
  2907.             FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
  2908.             FmtArg<A15>(v15)(), FmtArg<A16>(v16)());
  2909.     }
  2910.     template<class A1, class A2, class A3, class A4, class A5, class A6,
  2911.         class A7, class A8, class A9, class A10, class A11, class A12,
  2912.         class A13, class A14, class A15, class A16, class A17>
  2913.     void Format(const CT* szFmt, const A1& v1, const A2& v2, const A3& v3,
  2914.                 const A4& v4, const A5& v5, const A6& v6, const A7& v7,
  2915.                 const A8& v8, const A9& v9, const A10& v10, const A11& v11,
  2916.                 const A12& v12, const A13& v13, const A14& v14, const A15& v15,
  2917.                 const A16& v16, const A17& v17)
  2918.     {
  2919.         Fmt(szFmt, FmtArg<A1>(v1)(), FmtArg<A2>(v2)(),
  2920.             FmtArg<A3>(v3)(), FmtArg<A4>(v4)(), FmtArg<A5>(v5)(),
  2921.             FmtArg<A6>(v6)(), FmtArg<A7>(v7)(), FmtArg<A8>(v8)(),
  2922.             FmtArg<A9>(v9)(), FmtArg<A10>(v10)(),FmtArg<A11>(v11)(),
  2923.             FmtArg<A12>(v12)(),FmtArg<A13>(v13)(),FmtArg<A14>(v14)(),
  2924.             FmtArg<A15>(v15)(),FmtArg<A16>(v16)(),FmtArg<A17>(v17)());
  2925.     }
  2926.  
  2927. #else  // #ifdef SS_SAFE_FORMAT
  2928.  
  2929.  
  2930. #ifndef SS_ANSI
  2931.  
  2932.     void Format(UINT nId, ...)
  2933.     {
  2934.         va_list argList;
  2935.         va_start(argList, nId);
  2936.  
  2937.         MYTYPE strFmt;
  2938.         if ( strFmt.Load(nId) )
  2939.             FormatV(strFmt, argList);
  2940.  
  2941.         va_end(argList);
  2942.     }
  2943.     
  2944. #endif  // #ifdef SS_ANSI
  2945.  
  2946.     void Format(const CT* szFmt, ...)
  2947.     {
  2948.         va_list argList;
  2949.         va_start(argList, szFmt);
  2950.         FormatV(szFmt, argList);
  2951.         va_end(argList);
  2952.     }
  2953.  
  2954. #endif // #ifdef SS_SAFE_FORMAT
  2955.  
  2956.     void AppendFormat(const CT* szFmt, ...)
  2957.     {
  2958.         va_list argList;
  2959.         va_start(argList, szFmt);
  2960.         AppendFormatV(szFmt, argList);
  2961.         va_end(argList);
  2962.     }
  2963.  
  2964.     #define MAX_FMT_TRIES        5     // #of times we try 
  2965.     #define FMT_BLOCK_SIZE        2048 // # of bytes to increment per try
  2966.     #define BUFSIZE_1ST    256
  2967.     #define BUFSIZE_2ND 512
  2968.     #define STD_BUF_SIZE        1024
  2969.  
  2970.     // an efficient way to add formatted characters to the string.  You may only
  2971.     // add up to STD_BUF_SIZE characters at a time, though
  2972.     void AppendFormatV(const CT* szFmt, va_list argList)
  2973.     {
  2974.         CT szBuf[STD_BUF_SIZE];
  2975.     #ifdef SS_ANSI
  2976.         int nLen = ssvsprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);
  2977.     #else
  2978.         int nLen = ssnprintf(szBuf, STD_BUF_SIZE-1, szFmt, argList);
  2979.     #endif
  2980.         if ( 0 < nLen )
  2981.             this->append(szBuf, nLen);
  2982.     }
  2983.  
  2984.     // -------------------------------------------------------------------------
  2985.     // FUNCTION:  FormatV
  2986.     //        void FormatV(PCSTR szFormat, va_list, argList);
  2987.     //           
  2988.     // DESCRIPTION:
  2989.     //        This function formats the string with sprintf style format-specs. 
  2990.     //        It makes a general guess at required buffer size and then tries
  2991.     //        successively larger buffers until it finds one big enough or a
  2992.     //        threshold (MAX_FMT_TRIES) is exceeded.
  2993.     //
  2994.     // PARAMETERS: 
  2995.     //        szFormat - a PCSTR holding the format of the output
  2996.     //        argList - a Microsoft specific va_list for variable argument lists
  2997.     //
  2998.     // RETURN VALUE: 
  2999.     // -------------------------------------------------------------------------
  3000.  
  3001.     void FormatV(const CT* szFormat, va_list argList)
  3002.     {
  3003.     #ifdef SS_ANSI
  3004.  
  3005.         int nLen    = sslen(szFormat) + STD_BUF_SIZE;
  3006.         ssvsprintf(GetBuffer(nLen), nLen-1, szFormat, argList);
  3007.         ReleaseBuffer();
  3008.  
  3009.     #else
  3010.  
  3011.         CT* pBuf            = NULL;
  3012.         int nChars            = 1;
  3013.         int nUsed            = 0;
  3014.         size_type nActual    = 0;
  3015.         int nTry            = 0;
  3016.  
  3017.         do    
  3018.         {
  3019.             // Grow more than linearly (e.g. 512, 1536, 3072, etc)
  3020.  
  3021.             nChars            += ((nTry+1) * FMT_BLOCK_SIZE);
  3022.             pBuf            = reinterpret_cast<CT*>(_alloca(sizeof(CT)*nChars));
  3023.             nUsed            = ssnprintf(pBuf, nChars-1, szFormat, argList);
  3024.  
  3025.             // Ensure proper NULL termination.
  3026.  
  3027.             nActual            = nUsed == -1 ? nChars-1 : SSMIN(nUsed, nChars-1);
  3028.             pBuf[nActual+1]= '\0';
  3029.  
  3030.  
  3031.         } while ( nUsed < 0 && nTry++ < MAX_FMT_TRIES );
  3032.  
  3033.         // assign whatever we managed to format
  3034.  
  3035.         this->assign(pBuf, nActual);
  3036.  
  3037.     #endif
  3038.     }
  3039.  
  3040.     // -------------------------------------------------------------------------
  3041.     // CString Facade Functions:
  3042.     //
  3043.     // The following methods are intended to allow you to use this class as a
  3044.     // near drop-in replacement for CString.
  3045.     // -------------------------------------------------------------------------
  3046.     #ifdef SS_WIN32
  3047.         BSTR AllocSysString() const
  3048.         {
  3049.             ostring os;
  3050.             ssasn(os, *this);
  3051.             return ::SysAllocString(os.c_str());
  3052.         }
  3053.     #endif
  3054.  
  3055.     int Collate(PCMYSTR szThat) const
  3056.     {
  3057.         return sscoll(this->c_str(), this->length(), szThat, sslen(szThat));
  3058.     }
  3059.  
  3060.     int CollateNoCase(PCMYSTR szThat) const
  3061.     {
  3062.         return ssicoll(this->c_str(), this->length(), szThat, sslen(szThat));
  3063.     }
  3064.  
  3065.     int Compare(PCMYSTR szThat) const
  3066.     {
  3067.         return this->compare(szThat);    
  3068.     }
  3069.  
  3070.     int CompareNoCase(PCMYSTR szThat)    const
  3071.     {
  3072.         return ssicmp(this->c_str(), szThat);
  3073.     }
  3074.  
  3075.     int Delete(int nIdx, int nCount=1)
  3076.     {
  3077.         if ( nIdx < 0 )
  3078.             nIdx = 0;
  3079.  
  3080.         if ( nIdx < this->GetLength() )
  3081.             this->erase(static_cast<MYSIZE>(nIdx), static_cast<MYSIZE>(nCount));
  3082.  
  3083.         return GetLength();
  3084.     }
  3085.  
  3086.     void Empty()
  3087.     {
  3088.         this->erase();
  3089.     }
  3090.  
  3091.     int Find(CT ch) const
  3092.     {
  3093.         MYSIZE nIdx    = this->find_first_of(ch);
  3094.         return static_cast<int>(MYBASE::npos == nIdx  ? -1 : nIdx);
  3095.     }
  3096.  
  3097.     int Find(PCMYSTR szSub) const
  3098.     {
  3099.         MYSIZE nIdx    = this->find(szSub);
  3100.         return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
  3101.     }
  3102.  
  3103.     int Find(CT ch, int nStart) const
  3104.     {
  3105.         // CString::Find docs say add 1 to nStart when it's not zero
  3106.         // CString::Find code doesn't do that however.  We'll stick
  3107.         // with what the code does
  3108.  
  3109.         MYSIZE nIdx    = this->find_first_of(ch, static_cast<MYSIZE>(nStart));
  3110.         return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
  3111.     }
  3112.  
  3113.     int Find(PCMYSTR szSub, int nStart) const
  3114.     {
  3115.         // CString::Find docs say add 1 to nStart when it's not zero
  3116.         // CString::Find code doesn't do that however.  We'll stick
  3117.         // with what the code does
  3118.  
  3119.         MYSIZE nIdx    = this->find(szSub, static_cast<MYSIZE>(nStart));
  3120.         return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
  3121.     }
  3122.  
  3123.     int FindOneOf(PCMYSTR szCharSet) const
  3124.     {
  3125.         MYSIZE nIdx = this->find_first_of(szCharSet);
  3126.         return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
  3127.     }
  3128.  
  3129. #ifndef SS_ANSI
  3130.     void FormatMessage(PCMYSTR szFormat, ...) throw(std::exception)
  3131.     {
  3132.         va_list argList;
  3133.         va_start(argList, szFormat);
  3134.         PMYSTR szTemp;
  3135.         if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  3136.                        szFormat, 0, 0,
  3137.                        reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
  3138.              szTemp == 0 )
  3139.         {
  3140.             throw std::runtime_error("out of memory");
  3141.         }
  3142.         *this = szTemp;
  3143.         LocalFree(szTemp);
  3144.         va_end(argList);
  3145.     }
  3146.  
  3147.     void FormatMessage(UINT nFormatId, ...) throw(std::exception)
  3148.     {
  3149.         MYTYPE sFormat;
  3150.         VERIFY(sFormat.LoadString(nFormatId));
  3151.         va_list argList;
  3152.         va_start(argList, nFormatId);
  3153.         PMYSTR szTemp;
  3154.         if ( ssfmtmsg(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  3155.                        sFormat, 0, 0,
  3156.                        reinterpret_cast<PMYSTR>(&szTemp), 0, &argList) == 0 ||
  3157.             szTemp == 0)
  3158.         {
  3159.             throw std::runtime_error("out of memory");
  3160.         }
  3161.         *this = szTemp;
  3162.         LocalFree(szTemp);
  3163.         va_end(argList);
  3164.     }
  3165. #endif
  3166.  
  3167.     // GetAllocLength -- an MSVC7 function but it costs us nothing to add it.
  3168.  
  3169.     int GetAllocLength()
  3170.     {
  3171.         return static_cast<int>(this->capacity());
  3172.     }
  3173.  
  3174.     // -------------------------------------------------------------------------
  3175.     // GetXXXX -- Direct access to character buffer
  3176.     // -------------------------------------------------------------------------
  3177.     CT GetAt(int nIdx) const
  3178.     {
  3179.         return this->at(static_cast<MYSIZE>(nIdx));
  3180.     }
  3181.  
  3182.     CT* GetBuffer(int nMinLen=-1)
  3183.     {
  3184.         return GetBuf(nMinLen);
  3185.     }
  3186.  
  3187.     CT* GetBufferSetLength(int nLen)
  3188.     {
  3189.         return BufferSet(nLen);
  3190.     }
  3191.  
  3192.     // GetLength() -- MFC docs say this is the # of BYTES but
  3193.     // in truth it is the number of CHARACTERs (chars or wchar_ts)
  3194.     int GetLength() const
  3195.     {
  3196.         return static_cast<int>(this->length());
  3197.     }
  3198.     
  3199.     int Insert(int nIdx, CT ch)
  3200.     {
  3201.         if ( static_cast<MYSIZE>(nIdx) > this->size()-1 )
  3202.             this->append(1, ch);
  3203.         else
  3204.             this->insert(static_cast<MYSIZE>(nIdx), 1, ch);
  3205.  
  3206.         return GetLength();
  3207.     }
  3208.     int Insert(int nIdx, PCMYSTR sz)
  3209.     {
  3210.         if ( static_cast<MYSIZE>(nIdx) >= this->size() )
  3211.             this->append(sz, static_cast<MYSIZE>(sslen(sz)));
  3212.         else
  3213.             this->insert(static_cast<MYSIZE>(nIdx), sz);
  3214.  
  3215.         return GetLength();
  3216.     }
  3217.  
  3218.     bool IsEmpty() const
  3219.     {
  3220.         return this->empty();
  3221.     }
  3222.  
  3223.     MYTYPE Left(int nCount) const
  3224.     {
  3225.         // Range check the count.
  3226.  
  3227.         nCount = SSMAX(0, SSMIN(nCount, static_cast<int>(this->size())));
  3228.         return this->substr(0, static_cast<MYSIZE>(nCount)); 
  3229.     }
  3230.  
  3231. #ifndef SS_ANSI
  3232.     bool LoadString(UINT nId)
  3233.     {
  3234.         return this->Load(nId);
  3235.     }
  3236. #endif
  3237.  
  3238.     void MakeLower()
  3239.     {
  3240.         ToLower();
  3241.     }
  3242.  
  3243.     void MakeReverse()
  3244.     {
  3245.         std::reverse(this->begin(), this->end());
  3246.     }
  3247.  
  3248.     void MakeUpper()
  3249.     { 
  3250.         ToUpper();
  3251.     }
  3252.  
  3253.     MYTYPE Mid(int nFirst) const
  3254.     {
  3255.         return Mid(nFirst, this->GetLength()-nFirst);
  3256.     }
  3257.  
  3258.     MYTYPE Mid(int nFirst, int nCount) const
  3259.     {
  3260.         // CString does range checking here.  Since we're trying to emulate it,
  3261.         // we must check too.
  3262.  
  3263.         if ( nFirst < 0 )
  3264.             nFirst = 0;
  3265.         if ( nCount < 0 )
  3266.             nCount = 0;
  3267.  
  3268.         int nSize = static_cast<int>(this->size());
  3269.  
  3270.         if ( nFirst + nCount > nSize )
  3271.             nCount = nSize - nFirst;
  3272.  
  3273.         if ( nFirst > nSize )
  3274.             return MYTYPE();
  3275.  
  3276.         ASSERT(nFirst >= 0);
  3277.         ASSERT(nFirst + nCount <= nSize);
  3278.  
  3279.         return this->substr(static_cast<MYSIZE>(nFirst),
  3280.                             static_cast<MYSIZE>(nCount));
  3281.     }
  3282.  
  3283.     void ReleaseBuffer(int nNewLen=-1)
  3284.     {
  3285.         RelBuf(nNewLen);
  3286.     }
  3287.  
  3288.     int Remove(CT ch)
  3289.     {
  3290.         MYSIZE nIdx        = 0;
  3291.         int nRemoved    = 0;
  3292.         while ( (nIdx=this->find_first_of(ch)) != MYBASE::npos )
  3293.         {
  3294.             this->erase(nIdx, 1);
  3295.             nRemoved++;
  3296.         }
  3297.         return nRemoved;
  3298.     }
  3299.  
  3300.     int Replace(CT chOld, CT chNew)
  3301.     {
  3302.         int nReplaced    = 0;
  3303.  
  3304.         for ( MYITER iter=this->begin(); iter != this->end(); iter++ )
  3305.         {
  3306.             if ( *iter == chOld )
  3307.             {
  3308.                 *iter = chNew;
  3309.                 nReplaced++;
  3310.             }
  3311.         }
  3312.  
  3313.         return nReplaced;
  3314.     }
  3315.  
  3316.     int Replace(PCMYSTR szOld, PCMYSTR szNew)
  3317.     {
  3318.         int nReplaced        = 0;
  3319.         MYSIZE nIdx            = 0;
  3320.         MYSIZE nOldLen        = sslen(szOld);
  3321.  
  3322.         if ( 0 != nOldLen )
  3323.         {
  3324.             static const CT ch    = CT(0);
  3325.             MYSIZE nNewLen        = sslen(szNew);
  3326.             PCMYSTR szRealNew    = szNew == 0 ? &ch : szNew;
  3327.  
  3328.             while ( (nIdx=this->find(szOld, nIdx)) != MYBASE::npos )
  3329.             {
  3330.                 this->replace(this->begin()+nIdx, this->begin()+nIdx+nOldLen,
  3331.                     szRealNew);
  3332.  
  3333.                 nReplaced++;
  3334.                 nIdx += nNewLen;
  3335.             }
  3336.         }
  3337.  
  3338.         return nReplaced;
  3339.     }
  3340.  
  3341.     int ReverseFind(CT ch) const
  3342.     {
  3343.         MYSIZE nIdx    = this->find_last_of(ch);
  3344.         return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
  3345.     }
  3346.  
  3347.     // ReverseFind overload that's not in CString but might be useful
  3348.     int ReverseFind(PCMYSTR szFind, MYSIZE pos=MYBASE::npos) const
  3349.     {
  3350.         MYSIZE nIdx    = this->rfind(0 == szFind ? MYTYPE() : szFind, pos);
  3351.         return static_cast<int>(MYBASE::npos == nIdx ? -1 : nIdx);
  3352.     }
  3353.  
  3354.     MYTYPE Right(int nCount) const
  3355.     {
  3356.         // Range check the count.
  3357.  
  3358.         nCount = SSMAX(0, SSMIN(nCount, static_cast<int>(this->size())));
  3359.         return this->substr(this->size()-static_cast<MYSIZE>(nCount));
  3360.     }
  3361.  
  3362.     void SetAt(int nIndex, CT ch)
  3363.     {
  3364.         ASSERT(this->size() > static_cast<MYSIZE>(nIndex));
  3365.         this->at(static_cast<MYSIZE>(nIndex))        = ch;
  3366.     }
  3367.  
  3368. #ifndef SS_ANSI
  3369.     BSTR SetSysString(BSTR* pbstr) const
  3370.     {
  3371.         ostring os;
  3372.         ssasn(os, *this);
  3373.         if ( !::SysReAllocStringLen(pbstr, os.c_str(), os.length()) )
  3374.             throw std::runtime_error("out of memory");
  3375.  
  3376.         ASSERT(*pbstr != 0);
  3377.         return *pbstr;
  3378.     }
  3379. #endif
  3380.  
  3381.     MYTYPE SpanExcluding(PCMYSTR szCharSet) const
  3382.     {
  3383.         MYSIZE pos = this->find_first_of(szCharSet);
  3384.         return pos == MYBASE::npos ? *this : Left(pos);
  3385.     }
  3386.  
  3387.     MYTYPE SpanIncluding(PCMYSTR szCharSet) const
  3388.     {
  3389.         MYSIZE pos = this->find_first_not_of(szCharSet);
  3390.         return pos == MYBASE::npos ? *this : Left(pos);
  3391.     }
  3392.  
  3393. #if defined SS_WIN32 && !defined(UNICODE) && !defined(SS_ANSI)
  3394.  
  3395.     // CString's OemToAnsi and AnsiToOem functions are available only in
  3396.     // Unicode builds.  However since we're a template we also need a
  3397.     // runtime check of CT and a reinterpret_cast to account for the fact
  3398.     // that CStdStringW gets instantiated even in non-Unicode builds.
  3399.  
  3400.     void AnsiToOem()
  3401.     {
  3402.         if ( sizeof(CT) == sizeof(char) && !empty() )
  3403.         {
  3404.             ::CharToOem(reinterpret_cast<PCSTR>(this->c_str()),
  3405.                         reinterpret_cast<PSTR>(GetBuf()));
  3406.         }
  3407.         else
  3408.         {
  3409.             ASSERT(false);
  3410.         }
  3411.     }
  3412.  
  3413.     void OemToAnsi()
  3414.     {
  3415.         if ( sizeof(CT) == sizeof(char) && !empty() )
  3416.         {
  3417.             ::OemToChar(reinterpret_cast<PCSTR>(this->c_str()),
  3418.                         reinterpret_cast<PSTR>(GetBuf()));
  3419.         }
  3420.         else
  3421.         {
  3422.             ASSERT(false);
  3423.         }
  3424.     }
  3425.  
  3426. #endif
  3427.     
  3428.  
  3429.     // -------------------------------------------------------------------------
  3430.     // Trim and its variants
  3431.     // -------------------------------------------------------------------------
  3432.     MYTYPE& Trim()
  3433.     {
  3434.         return TrimLeft().TrimRight();
  3435.     }
  3436.  
  3437.     MYTYPE& TrimLeft()
  3438.     {
  3439.         this->erase(this->begin(),
  3440.             std::find_if(this->begin(), this->end(), NotSpace<CT>()));
  3441.  
  3442.         return *this;
  3443.     }
  3444.  
  3445.     MYTYPE&  TrimLeft(CT tTrim)
  3446.     {
  3447.         this->erase(0, this->find_first_not_of(tTrim));
  3448.         return *this;
  3449.     }
  3450.  
  3451.     MYTYPE&  TrimLeft(PCMYSTR szTrimChars)
  3452.     {
  3453.         this->erase(0, this->find_first_not_of(szTrimChars));
  3454.         return *this;
  3455.     }
  3456.  
  3457.     MYTYPE& TrimRight()
  3458.     {
  3459.         // NOTE:  When comparing reverse_iterators here (MYRITER), I avoid using
  3460.         // operator!=.  This is because namespace rel_ops also has a template
  3461.         // operator!= which conflicts with the global operator!= already defined
  3462.         // for reverse_iterator in the header <utility>.
  3463.         // Thanks to John James for alerting me to this.
  3464.  
  3465.         MYRITER it = std::find_if(this->rbegin(), this->rend(), NotSpace<CT>());
  3466.         if ( !(this->rend() == it) )
  3467.             this->erase(this->rend() - it);
  3468.  
  3469.         this->erase(!(it == this->rend()) ? this->find_last_of(*it) + 1 : 0);
  3470.         return *this;
  3471.     }
  3472.  
  3473.     MYTYPE&  TrimRight(CT tTrim)
  3474.     {
  3475.         MYSIZE nIdx    = this->find_last_not_of(tTrim);
  3476.         this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
  3477.         return *this;
  3478.     }
  3479.  
  3480.     MYTYPE&  TrimRight(PCMYSTR szTrimChars)
  3481.     {
  3482.         MYSIZE nIdx    = this->find_last_not_of(szTrimChars);
  3483.         this->erase(MYBASE::npos == nIdx ? 0 : ++nIdx);
  3484.         return *this;
  3485.     }
  3486.  
  3487.     void            FreeExtra()
  3488.     {
  3489.         MYTYPE mt;
  3490.         this->swap(mt);
  3491.         if ( !mt.empty() )
  3492.             this->assign(mt.c_str(), mt.size());
  3493.     }
  3494.  
  3495.     // I have intentionally not implemented the following CString
  3496.     // functions.   You cannot make them work without taking advantage
  3497.     // of implementation specific behavior.  However if you absolutely
  3498.     // MUST have them, uncomment out these lines for "sort-of-like"
  3499.     // their behavior.  You're on your own.
  3500.  
  3501. //    CT*                LockBuffer()    { return GetBuf(); }// won't really lock
  3502. //    void            UnlockBuffer(); { }    // why have UnlockBuffer w/o LockBuffer?
  3503.  
  3504.     // Array-indexing operators.  Required because we defined an implicit cast
  3505.     // to operator const CT* (Thanks to Julian Selman for pointing this out)
  3506.  
  3507.     CT& operator[](int nIdx)
  3508.     {
  3509.         return static_cast<MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
  3510.     }
  3511.  
  3512.     const CT& operator[](int nIdx) const
  3513.     {
  3514.         return static_cast<const MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
  3515.     }
  3516.  
  3517.     CT& operator[](unsigned int nIdx)
  3518.     {
  3519.         return static_cast<MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
  3520.     }
  3521.  
  3522.     const CT& operator[](unsigned int nIdx) const
  3523.     {
  3524.         return static_cast<const MYBASE*>(this)->operator[](static_cast<MYSIZE>(nIdx));
  3525.     }
  3526.  
  3527. #ifndef SS_NO_IMPLICIT_CAST
  3528.     operator const CT*() const
  3529.     {
  3530.         return this->c_str();
  3531.     }
  3532. #endif
  3533.  
  3534.     // IStream related functions.  Useful in IPersistStream implementations
  3535.  
  3536. #ifdef SS_INC_COMDEF
  3537.  
  3538.     // struct SSSHDR - useful for non Std C++ persistence schemes.
  3539.     typedef struct SSSHDR
  3540.     {
  3541.         BYTE    byCtrl;
  3542.         ULONG    nChars;
  3543.     } SSSHDR;    // as in "Standard String Stream Header"
  3544.  
  3545.     #define SSSO_UNICODE    0x01    // the string is a wide string
  3546.     #define SSSO_COMPRESS    0x02    // the string is compressed
  3547.  
  3548.     // -------------------------------------------------------------------------
  3549.     // FUNCTION: StreamSize
  3550.     // REMARKS:
  3551.     //        Returns how many bytes it will take to StreamSave() this CStdString
  3552.     //        object to an IStream.
  3553.     // -------------------------------------------------------------------------
  3554.     ULONG StreamSize() const
  3555.     {
  3556.         // Control header plus string
  3557.         ASSERT(this->size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
  3558.         return (this->size() * sizeof(CT)) + sizeof(SSSHDR);
  3559.     }
  3560.  
  3561.     // -------------------------------------------------------------------------
  3562.     // FUNCTION: StreamSave
  3563.     // REMARKS:
  3564.     //        Saves this CStdString object to a COM IStream.
  3565.     // -------------------------------------------------------------------------
  3566.     HRESULT StreamSave(IStream* pStream) const
  3567.     {
  3568.         ASSERT(size()*sizeof(CT) < 0xffffffffUL - sizeof(SSSHDR));
  3569.         HRESULT hr        = E_FAIL;
  3570.         ASSERT(pStream != 0);
  3571.         SSSHDR hdr;
  3572.         hdr.byCtrl        = sizeof(CT) == 2 ? SSSO_UNICODE : 0;
  3573.         hdr.nChars        = this->size();
  3574.  
  3575.  
  3576.         if ( FAILED(hr=pStream->Write(&hdr, sizeof(SSSHDR), 0)) )
  3577.         {
  3578.             TRACE(_T("StreamSave: Cannot write control header, ERR=0x%X\n"),hr);
  3579.         }
  3580.         else if ( empty() )
  3581.         {
  3582.             ;        // nothing to write
  3583.         }
  3584.         else if ( FAILED(hr=pStream->Write(this->c_str(),
  3585.             this->size()*sizeof(CT), 0)) )
  3586.         {
  3587.             TRACE(_T("StreamSave: Cannot write string to stream 0x%X\n"), hr);
  3588.         }
  3589.  
  3590.         return hr;
  3591.     }
  3592.  
  3593.  
  3594.     // -------------------------------------------------------------------------
  3595.     // FUNCTION: StreamLoad
  3596.     // REMARKS:
  3597.     //        This method loads the object from an IStream.
  3598.     // -------------------------------------------------------------------------
  3599.     HRESULT StreamLoad(IStream* pStream)
  3600.     {
  3601.         ASSERT(pStream != 0);
  3602.         SSSHDR hdr;
  3603.         HRESULT hr            = E_FAIL;
  3604.  
  3605.         if ( FAILED(hr=pStream->Read(&hdr, sizeof(SSSHDR), 0)) )
  3606.         {
  3607.             TRACE(_T("StreamLoad: Cant read control header, ERR=0x%X\n"), hr);
  3608.         }
  3609.         else if ( hdr.nChars > 0 )
  3610.         {
  3611.             ULONG nRead        = 0;
  3612.             PMYSTR pMyBuf    = BufferSet(hdr.nChars);
  3613.  
  3614.             // If our character size matches the character size of the string
  3615.             // we're trying to read, then we can read it directly into our
  3616.             // buffer. Otherwise, we have to read into an intermediate buffer
  3617.             // and convert.
  3618.             
  3619.             if ( (hdr.byCtrl & SSSO_UNICODE) != 0 )
  3620.             {
  3621.                 ULONG nBytes    = hdr.nChars * sizeof(wchar_t);
  3622.                 if ( sizeof(CT) == sizeof(wchar_t) )
  3623.                 {
  3624.                     if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
  3625.                         TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
  3626.                 }
  3627.                 else
  3628.                 {    
  3629.                     PWSTR pBufW = reinterpret_cast<PWSTR>(_alloca((nBytes)+1));
  3630.                     if ( FAILED(hr=pStream->Read(pBufW, nBytes, &nRead)) )
  3631.                         TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
  3632.                     else
  3633.                         sscpy(pMyBuf, pBufW, hdr.nChars);
  3634.                 }
  3635.             }
  3636.             else
  3637.             {
  3638.                 ULONG nBytes    = hdr.nChars * sizeof(char);
  3639.                 if ( sizeof(CT) == sizeof(char) )
  3640.                 {
  3641.                     if ( FAILED(hr=pStream->Read(pMyBuf, nBytes, &nRead)) )
  3642.                         TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
  3643.                 }
  3644.                 else
  3645.                 {
  3646.                     PSTR pBufA = reinterpret_cast<PSTR>(_alloca(nBytes));
  3647.                     if ( FAILED(hr=pStream->Read(pBufA, hdr.nChars, &nRead)) )
  3648.                         TRACE(_T("StreamLoad: Cannot read string: 0x%X\n"), hr);
  3649.                     else
  3650.                         sscpy(pMyBuf, pBufA, hdr.nChars);
  3651.                 }
  3652.             }
  3653.         }
  3654.         else
  3655.         {
  3656.             this->erase();
  3657.         }
  3658.         return hr;
  3659.     }
  3660. #endif // #ifdef SS_INC_COMDEF
  3661.  
  3662. #ifndef SS_ANSI
  3663.  
  3664.     // SetResourceHandle/GetResourceHandle.  In MFC builds, these map directly
  3665.     // to AfxSetResourceHandle and AfxGetResourceHandle.  In non-MFC builds they
  3666.     // point to a single static HINST so that those who call the member
  3667.     // functions that take resource IDs can provide an alternate HINST of a DLL
  3668.     // to search.  This is not exactly the list of HMODULES that MFC provides
  3669.     // but it's better than nothing.
  3670.  
  3671.     #ifdef _MFC_VER
  3672.         static void SetResourceHandle(HMODULE hNew)
  3673.         {
  3674.             AfxSetResourceHandle(hNew);
  3675.         }
  3676.         static HMODULE GetResourceHandle()
  3677.         {
  3678.             return AfxGetResourceHandle();
  3679.         }
  3680.     #else
  3681.         static void SetResourceHandle(HMODULE hNew)
  3682.         {
  3683.             SSResourceHandle() = hNew;
  3684.         }
  3685.         static HMODULE GetResourceHandle()
  3686.         {
  3687.             return SSResourceHandle();
  3688.         }
  3689.     #endif
  3690.  
  3691. #endif
  3692. };
  3693.  
  3694. // -----------------------------------------------------------------------------
  3695. // MSVC USERS: HOW TO EXPORT CSTDSTRING FROM A DLL
  3696. //
  3697. // If you are using MS Visual C++ and you want to export CStdStringA and
  3698. // CStdStringW from a DLL, then all you need to
  3699. //
  3700. //        1.    make sure that all components link to the same DLL version
  3701. //            of the CRT (not the static one).
  3702. //        2.    Uncomment the 3 lines of code below
  3703. //        3.    #define 2 macros per the instructions in MS KnowledgeBase
  3704. //            article Q168958.  The macros are:
  3705. //
  3706. //        MACRO        DEFINTION WHEN EXPORTING        DEFINITION WHEN IMPORTING
  3707. //        -----        ------------------------        -------------------------
  3708. //        SSDLLEXP    (nothing, just #define it)        extern
  3709. //        SSDLLSPEC    __declspec(dllexport)            __declspec(dllimport)
  3710. //
  3711. //        Note that these macros must be available to ALL clients who want to 
  3712. //        link to the DLL and use the class.  If they 
  3713. //
  3714. // A word of advice: Don't bother.
  3715. //
  3716. // Really, it is not necessary to export CStdString functions from a DLL.  I
  3717. // never do.  In my projects, I do generally link to the DLL version of the
  3718. // Standard C++ Library, but I do NOT attempt to export CStdString functions.
  3719. // I simply include the header where it is needed and allow for the code
  3720. // redundancy.
  3721. //
  3722. // That redundancy is a lot less than you think.  This class does most of its
  3723. // work via the Standard C++ Library, particularly the base_class basic_string<>
  3724. // member functions.  Most of the functions here are small enough to be inlined
  3725. // anyway.  Besides, you'll find that in actual practice you use less than 1/2
  3726. // of the code here, even in big projects and different modules will use as
  3727. // little as 10% of it.  That means a lot less functions actually get linked
  3728. // your binaries.  If you export this code from a DLL, it ALL gets linked in.
  3729. //
  3730. // I've compared the size of the binaries from exporting vs NOT exporting.  Take
  3731. // my word for it -- exporting this code is not worth the hassle.
  3732. //
  3733. // -----------------------------------------------------------------------------
  3734. //#pragma warning(disable:4231) // non-standard extension ("extern template")
  3735. //    SSDLLEXP template class SSDLLSPEC CStdStr<char>;
  3736. //    SSDLLEXP template class SSDLLSPEC CStdStr<wchar_t>;
  3737.  
  3738.  
  3739. // =============================================================================
  3740. //                        END OF CStdStr INLINE FUNCTION DEFINITIONS
  3741. // =============================================================================
  3742.  
  3743. //    Now typedef our class names based upon this humongous template
  3744.  
  3745. typedef CStdStr<char>        CStdStringA;    // a better std::string
  3746. typedef CStdStr<wchar_t>    CStdStringW;    // a better std::wstring
  3747. typedef CStdStr<OLECHAR>    CStdStringO;    // almost always CStdStringW
  3748.  
  3749. // -----------------------------------------------------------------------------
  3750. // CStdStr addition functions defined as inline
  3751. // -----------------------------------------------------------------------------
  3752.  
  3753.  
  3754. inline CStdStringA operator+(const CStdStringA& s1, const CStdStringA& s2)
  3755. {
  3756.     CStdStringA sRet(SSREF(s1));
  3757.     sRet.append(s2);
  3758.     return sRet;
  3759. }
  3760. inline CStdStringA operator+(const CStdStringA& s1, CStdStringA::value_type t)
  3761. {
  3762.     CStdStringA sRet(SSREF(s1));
  3763.     sRet.append(1, t);
  3764.     return sRet;
  3765. }
  3766. inline CStdStringA operator+(const CStdStringA& s1, PCSTR pA)
  3767. {
  3768.     CStdStringA sRet(SSREF(s1));
  3769.     sRet.append(pA);
  3770.     return sRet;
  3771. }
  3772. inline CStdStringA operator+(PCSTR pA, const CStdStringA& sA)
  3773. {
  3774.     CStdStringA sRet;
  3775.     CStdStringA::size_type nObjSize = sA.size();
  3776.     CStdStringA::size_type nLitSize = 
  3777.         static_cast<CStdStringA::size_type>(sslen(pA));
  3778.  
  3779.     sRet.reserve(nLitSize + nObjSize);
  3780.     sRet.assign(pA);
  3781.     sRet.append(sA);
  3782.     return sRet;
  3783. }
  3784.  
  3785.  
  3786. inline CStdStringA operator+(const CStdStringA& s1, const CStdStringW& s2)
  3787. {
  3788.     return s1 + CStdStringA(s2);
  3789. }
  3790. inline CStdStringW operator+(const CStdStringW& s1, const CStdStringW& s2)
  3791. {
  3792.     CStdStringW sRet(SSREF(s1));
  3793.     sRet.append(s2);
  3794.     return sRet;
  3795. }
  3796. inline CStdStringA operator+(const CStdStringA& s1, PCWSTR pW)
  3797. {
  3798.     return s1 + CStdStringA(pW);
  3799. }
  3800.  
  3801. #ifdef UNICODE
  3802.     inline CStdStringW operator+(PCWSTR pW, const CStdStringA& sA)
  3803.     {
  3804.         return CStdStringW(pW) + CStdStringW(SSREF(sA));
  3805.     }
  3806.     inline CStdStringW operator+(PCSTR pA, const CStdStringW& sW)
  3807.     {
  3808.         return CStdStringW(pA) + sW;
  3809.     }
  3810. #else
  3811.     inline CStdStringA operator+(PCWSTR pW, const CStdStringA& sA)
  3812.     {
  3813.         return CStdStringA(pW) + sA;
  3814.     }
  3815.     inline CStdStringA operator+(PCSTR pA, const CStdStringW& sW)
  3816.     {
  3817.         return pA + CStdStringA(sW);
  3818.     }
  3819. #endif
  3820.  
  3821. // ...Now the wide string versions.
  3822. inline CStdStringW operator+(const CStdStringW& s1, CStdStringW::value_type t)
  3823. {
  3824.     CStdStringW sRet(SSREF(s1));
  3825.     sRet.append(1, t);
  3826.     return sRet;
  3827. }
  3828. inline CStdStringW operator+(const CStdStringW& s1, PCWSTR pW)
  3829. {
  3830.     CStdStringW sRet(SSREF(s1));
  3831.     sRet.append(pW);
  3832.     return sRet;
  3833. }
  3834. inline CStdStringW operator+(PCWSTR pW, const CStdStringW& sW)
  3835. {
  3836.     CStdStringW sRet;
  3837.     CStdStringW::size_type nObjSize = sW.size();
  3838.     CStdStringA::size_type nLitSize = 
  3839.         static_cast<CStdStringW::size_type>(sslen(pW));
  3840.  
  3841.     sRet.reserve(nLitSize + nObjSize);
  3842.     sRet.assign(pW);
  3843.     sRet.append(sW);
  3844.     return sRet;
  3845. }
  3846.  
  3847. inline CStdStringW operator+(const CStdStringW& s1, const CStdStringA& s2)
  3848. {
  3849.     return s1 + CStdStringW(s2);
  3850. }
  3851. inline CStdStringW operator+(const CStdStringW& s1, PCSTR pA)
  3852. {
  3853.     return s1 + CStdStringW(pA);
  3854. }
  3855.  
  3856.  
  3857. // New-style format function is a template
  3858.  
  3859. #ifdef SS_SAFE_FORMAT
  3860.  
  3861. template<>
  3862. struct FmtArg<CStdStringA>
  3863. {
  3864.     explicit FmtArg(const CStdStringA& arg) : a_(arg) {}
  3865.     PCSTR operator()() const { return a_.c_str(); }
  3866.     const CStdStringA& a_;
  3867. private:
  3868.     FmtArg<CStdStringA>& operator=(const FmtArg<CStdStringA>&) { return *this; }
  3869. };
  3870. template<>
  3871. struct FmtArg<CStdStringW>
  3872. {
  3873.     explicit FmtArg(const CStdStringW& arg) : a_(arg) {}
  3874.     PCWSTR operator()() const { return a_.c_str(); }
  3875.     const CStdStringW& a_;
  3876. private:
  3877.     FmtArg<CStdStringW>& operator=(const FmtArg<CStdStringW>&) { return *this; }
  3878. };
  3879.  
  3880. template<>
  3881. struct FmtArg<std::string>
  3882. {
  3883.     explicit FmtArg(const std::string& arg) : a_(arg) {}
  3884.     PCSTR operator()() const { return a_.c_str(); }
  3885.     const std::string& a_;
  3886. private:
  3887.     FmtArg<std::string>& operator=(const FmtArg<std::string>&) { return *this; }
  3888. };
  3889. template<>
  3890. struct FmtArg<std::wstring>
  3891. {
  3892.     explicit FmtArg(const std::wstring& arg) : a_(arg) {}
  3893.     PCWSTR operator()() const { return a_.c_str(); }
  3894.     const std::wstring& a_;
  3895. private:
  3896.     FmtArg<std::wstring>& operator=(const FmtArg<std::wstring>&) {return *this;}
  3897. };
  3898. #endif // #ifdef SS_SAFEFORMAT
  3899.  
  3900. #ifndef SS_ANSI
  3901.     // SSResourceHandle: our MFC-like resource handle
  3902.     inline HMODULE& SSResourceHandle()
  3903.     {
  3904.         static HMODULE hModuleSS    = GetModuleHandle(0);
  3905.         return hModuleSS;
  3906.     }
  3907. #endif
  3908.  
  3909.  
  3910. // In MFC builds, define some global serialization operators
  3911. // Special operators that allow us to serialize CStdStrings to CArchives.
  3912. // Note that we use an intermediate CString object in order to ensure that
  3913. // we use the exact same format.
  3914.  
  3915. #ifdef _MFC_VER
  3916.     inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringA& strA)
  3917.     {
  3918.         CString strTemp    = strA;
  3919.         return ar << strTemp;
  3920.     }
  3921.     inline CArchive& AFXAPI operator<<(CArchive& ar, const CStdStringW& strW)
  3922.     {
  3923.         CString strTemp    = strW;
  3924.         return ar << strTemp;
  3925.     }
  3926.  
  3927.     inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringA& strA)
  3928.     {
  3929.         CString strTemp;
  3930.         ar >> strTemp;
  3931.         strA = strTemp;
  3932.         return ar;
  3933.     }
  3934.     inline CArchive& AFXAPI operator>>(CArchive& ar, CStdStringW& strW)
  3935.     {
  3936.         CString strTemp;
  3937.         ar >> strTemp;
  3938.         strW = strTemp;
  3939.         return ar;
  3940.     }
  3941. #endif    // #ifdef _MFC_VER -- (i.e. is this MFC?)
  3942.  
  3943.  
  3944.  
  3945. // -----------------------------------------------------------------------------
  3946. // GLOBAL FUNCTION:  WUFormat
  3947. //        CStdStringA WUFormat(UINT nId, ...);
  3948. //        CStdStringA WUFormat(PCSTR szFormat, ...);
  3949. //
  3950. // REMARKS:
  3951. //        This function allows the caller for format and return a CStdStringA
  3952. //        object with a single line of code.
  3953. // -----------------------------------------------------------------------------
  3954.  
  3955. inline CStdStringA WUFormatA(PCSTR szFormat, ...)
  3956. {
  3957.     va_list argList;
  3958.     va_start(argList, szFormat);
  3959.     CStdStringA strOut;
  3960.     strOut.FormatV(szFormat, argList);
  3961.     va_end(argList);
  3962.     return strOut;
  3963. }
  3964. inline CStdStringW WUFormatW(PCWSTR szwFormat, ...)
  3965. {
  3966.     va_list argList;
  3967.     va_start(argList, szwFormat);
  3968.     CStdStringW strOut;
  3969.     strOut.FormatV(szwFormat, argList);
  3970.     va_end(argList);
  3971.     return strOut;
  3972. }
  3973. #ifdef SS_ANSI
  3974. #else
  3975.     inline CStdStringA WUFormatA(UINT nId, ...)
  3976.     {
  3977.         va_list argList;
  3978.         va_start(argList, nId);
  3979.  
  3980.         CStdStringA strFmt;
  3981.         CStdStringA strOut;
  3982.         if ( strFmt.Load(nId) )
  3983.             strOut.FormatV(strFmt, argList);
  3984.  
  3985.         va_end(argList);
  3986.         return strOut;
  3987.     }
  3988.  
  3989.     inline CStdStringW WUFormatW(UINT nId, ...)
  3990.     {
  3991.         va_list argList;
  3992.         va_start(argList, nId);
  3993.  
  3994.         CStdStringW strFmt;
  3995.         CStdStringW strOut;
  3996.         if ( strFmt.Load(nId) )
  3997.             strOut.FormatV(strFmt, argList);
  3998.  
  3999.         va_end(argList);
  4000.         return strOut;
  4001.     }
  4002. #endif // #ifdef SS_ANSI
  4003.  
  4004.  
  4005.  
  4006. #if defined(SS_WIN32) && !defined (SS_ANSI)
  4007.     // -------------------------------------------------------------------------
  4008.     // FUNCTION: WUSysMessage
  4009.     //     CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
  4010.     //     CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID);
  4011.     //           
  4012.     // DESCRIPTION:
  4013.     //     This function simplifies the process of obtaining a string equivalent
  4014.     //     of a system error code returned from GetLastError().  You simply
  4015.     //     supply the value returned by GetLastError() to this function and the
  4016.     //     corresponding system string is returned in the form of a CStdStringA.
  4017.     //
  4018.     // PARAMETERS: 
  4019.     //     dwError - a DWORD value representing the error code to be translated
  4020.     //     dwLangId - the language id to use.  defaults to english.
  4021.     //
  4022.     // RETURN VALUE: 
  4023.     //     a CStdStringA equivalent of the error code.  Currently, this function
  4024.     //     only returns either English of the system default language strings.  
  4025.     // -------------------------------------------------------------------------
  4026.     #define SS_DEFLANGID MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)
  4027.     inline CStdStringA WUSysMessageA(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
  4028.     {
  4029.         CHAR szBuf[512];
  4030.  
  4031.         if ( 0 != ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
  4032.                                    dwLangId, szBuf, 511, NULL) )
  4033.             return WUFormatA("%s (0x%X)", szBuf, dwError);
  4034.         else
  4035.              return WUFormatA("Unknown error (0x%X)", dwError);
  4036.     }
  4037.     inline CStdStringW WUSysMessageW(DWORD dwError, DWORD dwLangId=SS_DEFLANGID)
  4038.     {
  4039.         WCHAR szBuf[512];
  4040.  
  4041.         if ( 0 != ::FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
  4042.                                    dwLangId, szBuf, 511, NULL) )
  4043.             return WUFormatW(L"%s (0x%X)", szBuf, dwError);
  4044.         else
  4045.              return WUFormatW(L"Unknown error (0x%X)", dwError);
  4046.     }
  4047. #endif
  4048.  
  4049. // Define TCHAR based friendly names for some of these functions
  4050.  
  4051. #ifdef UNICODE
  4052.     //#define CStdString                CStdStringW
  4053.     typedef CStdStringW                CStdString;
  4054.     #define WUSysMessage            WUSysMessageW
  4055.     #define WUFormat                WUFormatW
  4056. #else
  4057.     //#define CStdString                CStdStringA
  4058.     typedef CStdStringA                CStdString;
  4059.     #define WUSysMessage            WUSysMessageA
  4060.     #define WUFormat                WUFormatA
  4061. #endif
  4062.  
  4063. // ...and some shorter names for the space-efficient
  4064.  
  4065. #define WUSysMsg                    WUSysMessage
  4066. #define WUSysMsgA                    WUSysMessageA
  4067. #define WUSysMsgW                    WUSysMessageW
  4068. #define WUFmtA                        WUFormatA
  4069. #define    WUFmtW                        WUFormatW
  4070. #define WUFmt                        WUFormat
  4071. #define WULastErrMsg()                WUSysMessage(::GetLastError())
  4072. #define WULastErrMsgA()                WUSysMessageA(::GetLastError())
  4073. #define WULastErrMsgW()                WUSysMessageW(::GetLastError())
  4074.  
  4075.  
  4076. // -----------------------------------------------------------------------------
  4077. // FUNCTIONAL COMPARATORS:
  4078. // REMARKS:
  4079. //        These structs are derived from the std::binary_function template.  They
  4080. //        give us functional classes (which may be used in Standard C++ Library
  4081. //        collections and algorithms) that perform case-insensitive comparisons of
  4082. //        CStdString objects.  This is useful for maps in which the key may be the
  4083. //         proper string but in the wrong case.
  4084. // -----------------------------------------------------------------------------
  4085. #define StdStringLessNoCaseW        SSLNCW    // avoid VC compiler warning 4786
  4086. #define StdStringEqualsNoCaseW        SSENCW        
  4087. #define StdStringLessNoCaseA        SSLNCA        
  4088. #define StdStringEqualsNoCaseA        SSENCA        
  4089.  
  4090. #ifdef UNICODE
  4091.     #define StdStringLessNoCase        SSLNCW        
  4092.     #define StdStringEqualsNoCase    SSENCW        
  4093. #else
  4094.     #define StdStringLessNoCase        SSLNCA        
  4095.     #define StdStringEqualsNoCase    SSENCA        
  4096. #endif
  4097.  
  4098. struct StdStringLessNoCaseW
  4099.     : std::binary_function<CStdStringW, CStdStringW, bool>
  4100. {
  4101.     inline
  4102.     bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
  4103.     { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
  4104. };
  4105. struct StdStringEqualsNoCaseW
  4106.     : std::binary_function<CStdStringW, CStdStringW, bool>
  4107. {
  4108.     inline
  4109.     bool operator()(const CStdStringW& sLeft, const CStdStringW& sRight) const
  4110.     { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
  4111. };
  4112. struct StdStringLessNoCaseA
  4113.     : std::binary_function<CStdStringA, CStdStringA, bool>
  4114. {
  4115.     inline
  4116.     bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
  4117.     { return ssicmp(sLeft.c_str(), sRight.c_str()) < 0; }
  4118. };
  4119. struct StdStringEqualsNoCaseA
  4120.     : std::binary_function<CStdStringA, CStdStringA, bool>
  4121. {
  4122.     inline
  4123.     bool operator()(const CStdStringA& sLeft, const CStdStringA& sRight) const
  4124.     { return ssicmp(sLeft.c_str(), sRight.c_str()) == 0; }
  4125. };
  4126.  
  4127. // If we had to define our own version of TRACE above, get rid of it now
  4128.  
  4129. #ifdef TRACE_DEFINED_HERE
  4130.     #undef TRACE
  4131.     #undef TRACE_DEFINED_HERE
  4132. #endif
  4133.  
  4134.  
  4135. // These std::swap specializations come courtesy of Mike Crusader. 
  4136.  
  4137. //namespace std
  4138. //{
  4139. //    inline void swap(CStdStringA& s1, CStdStringA& s2) throw()
  4140. //    {
  4141. //        s1.swap(s2);
  4142. //    }
  4143. //    template<>
  4144. //    inline void swap(CStdStringW& s1, CStdStringW& s2) throw()
  4145. //    {
  4146. //        s1.swap(s2);
  4147. //    }
  4148. //}
  4149.  
  4150. // Turn back on any Borland warnings we turned off.
  4151.  
  4152. #ifdef __BORLANDC__
  4153.     #pragma option pop  // Turn back on inline function warnings
  4154. //    #pragma warn +inl   // Turn back on inline function warnings
  4155. #endif
  4156.  
  4157. #endif    // #ifndef STDSTRING_H
  4158.